diff --git a/content/_data/authors.yml b/content/_data/authors.yml new file mode 100644 index 000000000000..f15b60bdb399 --- /dev/null +++ b/content/_data/authors.yml @@ -0,0 +1,29 @@ +Olli Mukkula: + name : "Olli Mukkula" + bio : "Application Specialist at CSC, Quantum Technologies" + avatar : "/assets/images/authors/Olli_Mukkula.png" + +Joonas Nivala: + name : "Joonas Nivala" + bio : "Quantum Computing trainee at CSC, Quantum Technologies" + avatar : "/assets/images/authors/Joonas_Nivala.jpg" + +Nikolas Klemola Tango: + name : "Nikolas Klemola Tango" + bio : "Junior Application Specialist at CSC, Quantum Technologies" + avatar : "/assets/images/authors/Nikolas_Klemola_Tango.jpg" + +Huyen Do: + name : "Huyen Do" + bio : "Quantum Computing trainee at CSC, Quantum Technologies" + avatar : "/assets/images/authors/Huyen_Do.jpg" + +Meeri Makitalo: + name : "Meeri Mäkitalo" + bio : "Quantum Computing trainee at CSC, Quantum Technologies" + avatar : "/assets/images/authors/Meeri_Makitalo.jpg" + +Michael Mucciardi: + name : "Michael Mucciardi" + bio : "Senior Systems Specialist at CSC, Quantum Technologies" + avatar : "/assets/images/authors/Michael_Mucciardi.jpg" \ No newline at end of file diff --git a/content/_data/constants.yml b/content/_data/constants.yml index e9c63a352250..61842a6233c6 100644 --- a/content/_data/constants.yml +++ b/content/_data/constants.yml @@ -6,6 +6,8 @@ feedback_email: fiqci-feedback@postit.csc.fi header_nav: - title: Home page: pages/home.md + - title: About FiQCI + page: pages/about.md - title: Get access page: pages/access.md - title: Blogs and instructions @@ -38,7 +40,9 @@ access_cards: href: FIXME teaser: /assets/images/FiQCI-banner.jpg description: |- - The backbone of the classical HPC resources in FiQCI, and the portal for quantum computing resources, is the pan-European EuroHPC LUMI supercomputer. LUMI is the fastest and greenest supercomputer in Europe, hosted by CSC in Kajaani, Finland. + The backbone of the classical HPC resources in FiQCI, and the portal for quantum computing resources, + is the pan-European EuroHPC LUMI supercomputer. LUMI is the fastest and greenest supercomputer in Europe, + hosted by CSC in Kajaani, Finland. links: - title: Getting started with Lumi href: https://www.lumi-supercomputer.eu/get-started/ @@ -46,7 +50,9 @@ access_cards: href: FIXME teaser: /assets/images/vtt-images/VTT_lab-2.jpg description: |- - Helmi, the first Finnish quantum computer, co-developed by VTT and IQM Quantum Computers, is operated by VTT in Espoo, Finland. Helmi is based on superconducting technology, and presently provides five qubits. Upgrades to 20, then 50 qubits is planned for the near future. + Helmi, the first Finnish quantum computer, co-developed by VTT and IQM Quantum Computers, + is operated by VTT in Espoo, Finland. Helmi is based on superconducting technology, + and presently provides five qubits. Upgrades to 20, then 50 qubits is planned for the near future. links: - title: How to access Helmi, instructions href: FIXME @@ -56,18 +62,145 @@ access_cards: href: FIXME teaser: /assets/images/FiQCI-banner.jpg description: |- - Kvasi, the Atos Quantum Learning Machine or Qaptiva is a quantum computing simulator with which you can learn to use and develop new quantum algorithms. Kvasi provides a platform for developing and simulating quantum algorithms in both ideal and realistic, noisy conditions. Kvasi is capable of simulating algorithms for quantum computers of 30+ qubits. + Kvasi, the Atos Quantum Learning Machine or Qaptiva is a quantum computing simulator with which you can learn + to use and develop new quantum algorithms. Kvasi provides a platform for developing and simulating quantum + algorithms in both ideal and realistic, noisy conditions. Kvasi is capable of simulating algorithms for + quantum computers of 30+ qubits. links: - title: How to access Kvasi, instructions href: FIXME - title: Read more about Kvasi href: FIXME +quantum_resources: + - name: Helmi + desc: |- + Helmi (VTT Q5), the Finnish quantum computer operated by VTT, co-developed with IQM. + Helmi is based on superconducting technology, and presently provides five qubits. + Upgrades to 20, then 50 qubits is planned for the near future. Helmi is accessible + through the LUMI supercomputer environment. The pilot phase for Helmi access is now running! + image: "/assets/images/vtt-images/VTT_lab-2.jpg" + links: + - link: "" + teaser: "How to access Helmi, instructions" + icon: mdiArrowRight + - link: "" + teaser: "Read more about Helmi (VTT website)" + icon: mdiOpenInNew + + - name: VTT Q50 + desc: |- + Lorem ipsum the Finnish quantum computer operated by VTT, co-developed with IQM. + Lorem ipsum is accessible through the LUMI supercomputer environment. The pilot phase + for VTT Q50 access is now running! + image: "/assets/images/vtt-images/VTT_lab-2.jpg" + links: + - link: "" + teaser: "How to access VTT Q50, instructions" + icon: mdiArrowRight + - link: "" + teaser: "Read more about VTT Q50 (VTT website)" + icon: mdiOpenInNew + +supercomputer_resources: + - name: LUMI + desc: |- + The backbone of the classical HPC resources in FiQCI, and the portal for quantum computing resources, + is the pan-European EuroHPC LUMI supercomputer. LUMI is the fastest and greenest supercomputer in Europe, + hosted by CSC in Kajaani, Finland. + image: "/assets/images/FiQCI-banner.jpg" + links: + - link: "" + teaser: "How to access Lumi" + icon: mdiArrowRight + - link: "" + teaser: "Read more about LUMI (LUMI website)" + icon: mdiOpenInNew + +emulation_resources: + - name: Quantum emuation with LUMI + desc: |- + With the LUMI supercomputer it is possible to emulate quantum computer with upto 40+ qubits. + image: "/assets/images/FiQCI-banner.jpg" + links: + - link: "" + teaser: "Quantum emulation dosumentation" + icon: mdiArrowRight + +about: + desc: |- + The Finnish Quantum-Computing Infrastructure (FiQCI) was established in 2020, when it became + part of the Finnish Research Infrastructure (FIRI) roadmap of significant national research + infrastructures within the Finnish research infrastructure ecosystem, maintained by the + Research Council of Finland. + + mission: |- + The mission of FiQCI is to provide state-of-the-art quantum-computing services such as + computing time and training to the Finnish RDI communities. This includes providing a + hybrid high-performance computing and quantum computing (HPC+QC) platform for developing, + testing, and exploiting quantum-accelerated computational workflows. Through FiQCI, Finnish + researchers have access to one of the most powerful hybrid HPC+nQC resources in the world, + available for quantum accelerated research and development. The infrastructure also aims to + offer possibilities to carry out experiments in quantum physics. + + maintain: |- + FiQCI is jointly maintained, operated, and developed by VTT, Aalto University, and + CSC - IT Center for Science. + + advisory-group: + desc: |- + The Scientific and Technical Advisory Group (STAG) provides input for the operation + of the infrastructure. The current (2023) members of the STAG are: + people: + - name: Dr. Valeria Bartsch + institution: Fraunhofer Institute for Industrial Mathematics + country: Germany + + - name: Dr. Alba Cervera Lierta + institution: Barcelona Supercomputing Center + country: Spain + + - name: Prof. Tommi Mikkonen + institution: University of Jyväskylä + country: Finland + + - name: Prof. Martin Schulz + institution: Technical University of Munich + country: Germany + + - name: Prof. Göran Wendin + institution: Chalmers University of Technology + country: Sweden + + management: + people: + - name: Prof. Mika Prunnila + institution: VTT + title: FiQCI director + + - name: Dr. Mikael Johansson + institution: CSC + title: FiQCI vice-director + + - name: Prof. Tapio Ala-Nissilä + institution: Aalto University + title: FiQCI vice-director + + acknowledgement: + desc: |- + When publishing the results that utilise the FiQCI infrastructure, users should acknowledge + the use of FiQCI, preferably in the format: "These results have been acquired using the + Finnish Quantum-Computing Infrastructure + + helmi-link-url: /publications/2022-11-01-Helmi_pilot + helmi-link-text: Additionally, users should also acknowledge using Helmi if applicable + logo: assets/images/FiQCI-logo.png favicon: assets/images/favicon.png footer_icons: assets/footer-icons funder_logos: assets/images/funders description: >- - Web presence of the Finnish Quantum-Computing Infrastructure. We provide state-of-the-art quantum-computing services to Finnish RDI communities. + Web presence of the Finnish Quantum-Computing Infrastructure. We provide state-of-the-art quantum-computing + services to Finnish RDI communities. excerpt_max_length: 250 title_separator: " – " diff --git a/content/_includes/head.html b/content/_includes/head.html index 8c94b778f109..604e7601edd4 100644 --- a/content/_includes/head.html +++ b/content/_includes/head.html @@ -11,8 +11,10 @@ {% include external/mathjax.html -%} {% include external/font.html %} - {% if page.react %} + {% if page.react and (site.pages | where: "name" page.name) %} {%- assign react_source = page.name | append: ".js" -%} + {% elsif (site.collections | where: "label" page.collection) %} + {%- assign react_source = page.layout | append: ".js" %} {% else %} {%- assign react_source = "default.js" -%} {% endif %} diff --git a/content/_includes/react/root.html b/content/_includes/react/root.html index 5ffebb03f347..3132e0260177 100644 --- a/content/_includes/react/root.html +++ b/content/_includes/react/root.html @@ -1 +1 @@ -
+
\ No newline at end of file diff --git a/content/_includes/react/section-root.html b/content/_includes/react/section-root.html index 74dfd1e8e5ef..2f8e3a989c3a 100644 --- a/content/_includes/react/section-root.html +++ b/content/_includes/react/section-root.html @@ -1,4 +1,4 @@ -
+

{{ include.heading }}

diff --git a/content/_layouts/base.html b/content/_layouts/base.html index 64410e29ac36..a3c68b364570 100644 --- a/content/_layouts/base.html +++ b/content/_layouts/base.html @@ -5,7 +5,7 @@ {%- include react/root.html id='react-root' -%} - +
{{ content }}
diff --git a/content/_layouts/home.html b/content/_layouts/home.html index 1a046ddf1e06..32e0efdbd57c 100644 --- a/content/_layouts/home.html +++ b/content/_layouts/home.html @@ -2,8 +2,116 @@ layout: base --- +{% assign about_data = site.data.constants.about %} + {%- include react/root.html id='hero' -%} {{ content }} -{%- include react/root.html id='about-fiqci' -%} +
+
+
+ + +
+
+
+

FiQCI mission

+
+
+
+

+ Through FiQCI, Finnish researchers have access to one of the most + powerful hybrid HPC+nQC resources in the world. +

+

+ Available for quantum-accelerated research and development. +

+
+
+
+

+ {{ about_data.mission }} +

+

+ {{ about_data.maintain }} +

+ + + + +
+
+
+
+
+
\ No newline at end of file diff --git a/content/_layouts/page.html b/content/_layouts/page.html index 5466cbbc8a25..a089e4d84f42 100644 --- a/content/_layouts/page.html +++ b/content/_layouts/page.html @@ -4,10 +4,12 @@ {%- include react/root.html id='banner' -%} -
- -
+
+
+
+ {%- include react/root.html id='breadcrumbs' -%} +
+ {{ content }}
- -
+ diff --git a/content/_layouts/post.html b/content/_layouts/post.html index 19410d08eb03..9ae6d505a855 100644 --- a/content/_layouts/post.html +++ b/content/_layouts/post.html @@ -1,24 +1,45 @@ --- layout: base +react: true --- -{% assign constants = site.data.constants %} -
-
-

{{ page.title | escape }}

-

- - {%- if page.author -%} - • - {%- endif -%} -

-
+{% assign constants = site.data.constants %} +{% assign author_info = site.data.authors[page.author] %} -
- {{ content }} -
+{%- include react/root.html id='banner' -%} -
+
+
+
+
+ {%- include react/root.html id='breadcrumbs' -%} +
+
+
+ Author +
+

{{author_info.name}}

+

{{author_info.bio}}

+
+
+
+
+ {%- include react/root.html id='tags' -%} + +

{{page.title}}

+
+ {{ content }} +
+
+ {%- include react/root.html id='references-accordion' -%} +
+
+
+ {%- include react/root.html id='read-next' -%} +
+
+
+
\ No newline at end of file diff --git a/content/pages/about.md b/content/pages/about.md index 5c111746756c..4865a5eb8d81 100644 --- a/content/pages/about.md +++ b/content/pages/about.md @@ -2,55 +2,40 @@ layout: page title: About subtitle: The FiQCI consortium maintains, operates, and develops the infrastructure +react: true --- -## In Brief - -The Finnish Quantum-Computing Infrastructure (FiQCI) was established in 2020, when it became part of the Finnish Research Infrastructure (FIRI) roadmap of significant national research infrastructures within the Finnish research infrastructure ecosystem, maintained by the Research Council of Finland. - -The mission of FiQCI is to provide state-of-the-art quantum-computing services such as computing time and training to the Finnish RDI communities. This includes providing a hybrid high-performance computing and quantum computing (HPC+QC) platform for developing, testing, and exploiting quantum-accelerated computational workflows. Through FiQCI, Finnish researchers have access to one of the most powerful hybrid HPC+nQC resources in the world, available for quantum accelerated research and development. The infrastructure also aims to offer possibilities to carry out experiments in quantum physics. - -FiQCI is jointly maintained, operated, and developed by **VTT**, **Aalto University**, and **CSC – IT Center for Science**. - -## Components - -### LUMI supercomputer - -The backbone of the classical HPC resources in FiQCI, and the portal for quantum computing resources, is the pan-European EuroHPC LUMI supercomputer. LUMI is the fastest and greenest supercomputer in Europe, hosted by CSC in Kajaani, Finland. For more information, see [https://www.lumi-supercomputer.eu/](https://www.lumi-supercomputer.eu/) - -### Helmi quantum computer - -Helmi, the first Finnish quantum computer, co-developed by VTT and IQM Quantum Computers, is operated by VTT in Espoo, Finland. Helmi is based on superconducting technology, and presently provides five qubits. Upgrades to 20, then 50 qubits is planned for the near future. - -### Kvasi quantum computer simulator - -Kvasi, the Atos Quantum Learning Machine or Qaptiva is a quantum computing simulator with which you can learn to use and develop new quantum algorithms. Kvasi provides a platform for developing and simulating quantum algorithms in both ideal and realistic, noisy conditions. Kvasi is capable of simulating algorithms for quantum computers of 30+ qubits. For more information, see [https://research.csc.fi/-/kvasi](https://research.csc.fi/-/kvasi) - -### Other resources - -Other quantum resources will continuously be added to the FiQCI infrastructure. - -## Scientific and Technical Advisory Group - -The Scientific and Technical Advisory Group (STAG) provides input for the operation of the infrastructure. The current (2023) members of the STAG are: - -* Dr. Valeria Bartsch, Fraunhofer Institute for Industrial Mathematics, Germany -* Dr. Alba Cervera Lierta, Barcelona Supercomputing Center, Spain -* Prof. Tommi Mikkonen, University of Jyväskylä, Finland -* Prof. Martin Schulz, Technical University of Munich, Germany -* Prof. Göran Wendin, Chalmers University of Technology, Sweden - -## Management - -* Prof. Mika Prunnila, VTT, FiQCI director -* Dr. Mikael Johansson, CSC, FiQCI vice-director -* Prof. Tapio Ala-Nissilä, Aalto University, FiQCI vice-director - -## Acknowledgement - -When publishing the results that utilise the FiQCI infrastructure, users should acknowledge the use of FiQCI, preferably in the format: "These [results] have been acquired using the Finnish Quantum-Computing Infrastructure (https://fiqci.fi)". [Additionally, users should also acknowledge using Helmi if applicable](./posts/2022-11-01-Helmi-pilot.md#acknowledgement). - - -## Supported by - -TODO +{% assign about_data = site.data.constants.about %} + +
+

About FiQCI

+
+

{{ about_data.desc }}

+
+

{{ about_data.mission }}

+
+

{{ about_data.maintain }}

+
+
+

Scientific and Technical Advisory Group

+

{{ about_data.advisory-group.desc }}

+
    + {% for member in about_data.advisory-group.people %} +
  • {{ member.name }}, {{ member.institution }}, {{ member.country }}
  • + {% endfor %} +
+ +

Management

+
    + {% for mgr in about_data.advisory-group.management.people %} +
  • {{ mgr.name }}, {{ mgr.institution }}, {{ mgr.title }}
  • + {% endfor %} +
+ +

Acknowledgement

+

{{ about_data.advisory-group.acknowledgement.desc }} "Finnish Quantum-Computing Infrastructure (https://fiqci.fi)". + + {{ about_data.advisory-group.acknowledgement.helmi-link-text }} +

+
+
diff --git a/content/pages/access.md b/content/pages/access.md index 1a0f5cb87714..d6478f139ca5 100644 --- a/content/pages/access.md +++ b/content/pages/access.md @@ -2,25 +2,7 @@ title: How to get access layout: page subtitle: Access to FiQCI is granted through the CSC supercomputing environment +react: true --- -## Accessing the FiQCI infrastructure - -The main access portal to the real quantum computing resources is through the LUMI supercomputer environment. Kvasi, the Quantum Learning Machine can be accessed directly. - -### Access to Helmi - -The pilot phase for Helmi access is now running! [More details here](_posts/2022-11-01-Helmi-pilot/), with instructions on how to apply for a pilot project. - -Getting started [here](_posts/2024-08-23-Lumi_web_introduction/) with instructions how to interact with Helmi though LUMI web interface. - -### Access to Kvasi - -See the [Kvasi documentation](https://docs.csc.fi/computing/quantum-computing/overview/#kvasi) for details on how to connect to Kvasi. - -### Access to LUMI - -See the [LUMI webpage](https://www.lumi-supercomputer.eu/get-started-2021/users-in-finland/) for details on how to get access to the LUMI environment. - - - +{%- include react/root.html id='access' -%} \ No newline at end of file diff --git a/content/pages/home.md b/content/pages/home.md index fa482e1779f7..985a20ce91e1 100644 --- a/content/pages/home.md +++ b/content/pages/home.md @@ -9,4 +9,4 @@ permalink: / {% include react/section-root.html id='blog-cards' heading='Blogs and instructions' %} -{% include react/section-root.html id='event-cards' heading='Events' %} +{% include react/section-root.html id='event-cards' heading='Events' %} \ No newline at end of file diff --git a/content/store.js.liquid b/content/store.js.liquid index eb158d051588..41826370d212 100644 --- a/content/store.js.liquid +++ b/content/store.js.liquid @@ -37,30 +37,27 @@ permalink: store.js {%- capture pages -%} [ - {% assign first_item = true %} - {% for page in site.pages %} - {% unless page.path contains '.js' %} - {% if first_item %} - {% assign first_item = false %} - {% else %} - , - {% endif %} - { - "key": "{{ page.url | slugify }}", - "title": "{{ page.title | xml_escape }}", - "content": {{ page.content | strip_html | strip_newlines | jsonify }}, - "url": "{{ page.url | xml_escape }}", - "tags": [], - "type": "page" - } - {% endunless %} - {% endfor %} + {%- assign filtered_pages = site.pages | where_exp: "page", "page.url contains '/'" -%} + {%- assign filtered_pages = filtered_pages | reject: "url", "/404.html" -%} + {%- assign filtered_pages = filtered_pages | reject: "url", "/api/" -%} + {%- for page in filtered_pages -%} + {%- unless page.url contains '.json' or page.url contains '.css' or page.url contains '.js' or page.path contains '/api/' -%} + { + "key": "{{ page.url | slugify }}", + "title": {{ page.title | default: "" | jsonify }}, + "content": {{ page.content | default: "" | strip_html | strip_newlines | jsonify }}, + "url": {{ page.url | jsonify }}, + "tags": [], + "type": "page" + }{% unless forloop.last %},{% endunless %} + {%- endunless -%} + {%- endfor -%} ] {%- endcapture -%} const STORE = { - blogs: JSON.parse(String.raw`{{- blogs -}}`), - events: JSON.parse(String.raw`{{- events -}}`), - pages: JSON.parse(String.raw`{{- pages -}}`), -} + blogs: {{blogs}}, + events: {{events}}, + pages: {{pages}} +}; diff --git a/package-lock.json b/package-lock.json index 5d5801674850..e777e8ea0edc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,12 @@ "dependencies": { "@cscfi/csc-ui": "^2.3.0", "@cscfi/csc-ui-react": "^2.3.0", - "lunr": "^2.3.9" + "dompurify": "^3.2.4", + "front-matter": "^4.0.2", + "gray-matter": "^4.0.3", + "katex": "^0.16.21", + "lunr": "^2.3.9", + "prismjs": "^1.30.0" }, "devDependencies": { "@babel/core": "^7.26.0", @@ -2026,6 +2031,13 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", @@ -3158,6 +3170,15 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, + "node_modules/dompurify": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz", + "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/domutils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", @@ -3283,6 +3304,19 @@ "node": ">=8.0.0" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -3336,6 +3370,18 @@ "node": ">=0.8.x" } }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3579,6 +3625,37 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/front-matter": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", + "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1" + } + }, + "node_modules/front-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/front-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -3657,6 +3734,43 @@ "dev": true, "license": "ISC" }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -3842,6 +3956,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -4012,11 +4135,35 @@ "node": ">=6" } }, + "node_modules/katex": { + "version": "0.16.21", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.21.tgz", + "integrity": "sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -4801,6 +4948,15 @@ "dev": true, "license": "MIT" }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -5136,6 +5292,19 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -5249,6 +5418,12 @@ "source-map": "^0.6.0" } }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, "node_modules/ssr-window": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-4.0.2.tgz", @@ -5368,6 +5543,15 @@ "node": ">=8" } }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/style-loader": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", diff --git a/package.json b/package.json index acdff23819ea..eb6036cb4cd5 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ }, "webpack": { "outputDir": "./dist", - "reactPagesDir": "./src/pages" + "reactPagesDir": "./src/pages, ./src/views" }, "tailwindcss": { "inputDir": "./src/stylesheets" @@ -52,7 +52,12 @@ "dependencies": { "@cscfi/csc-ui": "^2.3.0", "@cscfi/csc-ui-react": "^2.3.0", - "lunr": "^2.3.9" + "dompurify": "^3.2.4", + "front-matter": "^4.0.2", + "gray-matter": "^4.0.3", + "katex": "^0.16.21", + "lunr": "^2.3.9", + "prismjs": "^1.30.0" }, "private": "true" } diff --git a/src/components/AboutFiqci.jsx b/src/components/AboutFiqci.jsx deleted file mode 100644 index 8cd5bb60de29..000000000000 --- a/src/components/AboutFiqci.jsx +++ /dev/null @@ -1,96 +0,0 @@ -import React from "react"; - -export const AboutFiqci = () => { - return ( -
- -
-
-
-
-
-

About FiQCI

-
-
-

- The Finnish Quantum-Computing Infrastructure (FiQCI) was established - in 2020, when it became part of the Finnish Research Infrastructure - (FIRI) roadmap of significant national research infrastructures - within the Finnish research infrastructure ecosystem, maintained by - the Research Council of Finland. -

-

- The mission of FiQCI is to provide state-of-the-art quantum-computing - services such as computing time and training to the Finnish RDI - communities. This includes providing a hybrid high-performance - computing and quantum computing (HPC+QC) platform for developing, - testing, and exploiting quantum-accelerated computational workflows. -

-

- FiQCI is jointly maintained, operated, and developed by VTT, Aalto - University, and CSC – IT Center for Science. -

-
-
-
-
-

- Through FiQCI, Finnish researchers have access to one of the most - powerful hybrid HPC+nQC resources in the world. -

-

- Available for quantum-accelerated research and development. -

-
-
-
- - -
-

- Scientific and Technical Advisory Group -

-
    -
  • - Dr. Alba Cervera Lierta, Barcelona Supercomputing Center, Spain -
  • -
  • Prof. Tommi Mikkonen, University of Jyväskylä, Finland
  • -
  • - Prof. Martin Schulz, Technical University of Munich, Germany -
  • -
  • - Prof. Göran Wendin, Chalmers University of Technology, Sweden -
  • -
-
- -
-

Management

-
    -
  • Prof. Mika Prunnila, VTT, FiQCI director
  • -
  • Dr. Mikael Johansson, CSC, FiQCI vice-director
  • -
  • Prof. Tapio Ala-Nissilä, Aalto University, FiQCI vice-director
  • -
-
- -
-

Acknowledgement

-

- When publishing the results that utilise the FiQCI infrastructure, - users should acknowledge the use of FiQCI, preferably in the format: - - {" "} - "These [results] have been acquired using the Finnish - Quantum-Computing Infrastructure (https://fiqci.fi)". - - - Additionally, users should also acknowledge using Helmi if - applicable. - -

-
-
-
-
- ); -}; diff --git a/src/components/AccessCards.jsx b/src/components/AccessCards.jsx index 38e7f2d0bf86..bfaa3f9641e9 100644 --- a/src/components/AccessCards.jsx +++ b/src/components/AccessCards.jsx @@ -6,37 +6,40 @@ import { prependBaseURL, isExternal } from '../utils/url'; import { useJsonApi } from '../hooks/useJsonApi'; -const AccessCardComponent = ({ title, href, teaser, description, links }) => - +const AccessCardComponent = ({ title, href, teaser, description, links }) => { + return ( + teaser - - {title} - - -
{description}
- -
- {links.map((link, index) => ( - - {link.title} - - ))} -
+ + {title} + + +
{description}
+ +
+ {links.map((link, index) => ( + + {link.title} + + ))} +
-
- +
+ ); + }; + export const AccessCards = props => { const accessCardComponents = props.cards?.map(card => ()) return <> -
+
{accessCardComponents}
diff --git a/src/components/Banner.jsx b/src/components/Banner.jsx index 3f88188cf012..bd1da567179b 100644 --- a/src/components/Banner.jsx +++ b/src/components/Banner.jsx @@ -3,8 +3,8 @@ import React from 'react'; export const Banner = ({ title }) => { return (
-
-
+
+

{title}

diff --git a/src/components/BlogCards.jsx b/src/components/BlogCards.jsx index 9292a32e371b..8813763c8ed2 100644 --- a/src/components/BlogCards.jsx +++ b/src/components/BlogCards.jsx @@ -7,7 +7,7 @@ export const BlogCardComponent = props => { const type = props?.filters?.Type ? Object.entries(props?.filters?.Type)?.filter(field => field[1])[0][0] : "News"; return ( {/* Adjusted card width */} - Logo {/* Reduced image height */} + Logo
{ export const BlogCards = () => { return ( - <> +
+
{ SITE.publications.slice(-5).reverse().map(blog => ) }
); }; diff --git a/src/components/BlogTags.jsx b/src/components/BlogTags.jsx new file mode 100644 index 000000000000..028f79eba562 --- /dev/null +++ b/src/components/BlogTags.jsx @@ -0,0 +1,26 @@ +import React, { useState } from 'react'; +import { CTag, CTags } from '@cscfi/csc-ui-react'; + +export const BlogTags = ({ tags }) => { + const [activeTags, setActiveTags] = useState(new Array(tags.length).fill(false)); + return ( + + {tags.map((tag, index) => ( +
+ setActiveTags(prev => { + const newActiveTags = [...prev]; + newActiveTags[index] = !newActiveTags[index]; + return newActiveTags; + })} + key={index} + className={`blog-tag ${activeTags[index] ? 'active' : ''}`} + active={activeTags[index]} + > + {tag} + +
+ ))} +
+ ); +} \ No newline at end of file diff --git a/src/components/Blogs.jsx b/src/components/Blogs.jsx index 7f79c12fabb8..0b82fee80f43 100644 --- a/src/components/Blogs.jsx +++ b/src/components/Blogs.jsx @@ -5,7 +5,6 @@ import { CCardTitle, CCardContent, CCardActions } from '@cscfi/csc-ui-react'; import { BlogCardComponent } from './BlogCards'; -import { Breadcrumbs } from './Breadcrumbs'; const BlogFilters = ({ filters, handleFilterChange }) => { const handleCheckboxChange = useCallback((category, option) => { @@ -210,24 +209,19 @@ export const Blogs = () => { }; return ( -
-
-
- -
-
- -
-
- -
+
+
+ +
+
+
{ - const entries = Object.entries(breadcrumbs); - return ( -
- {entries.map(([label, href], index) => { - const isLast = index === entries.length - 1; - return ( - - {isLast ? ( -

{label}

- ) : ( - - {label}  >  - - )} -
- ); - })} -
- ); + const entries = Object.entries(breadcrumbs); + return ( +
+ {entries.map(([label, href], index) => { + label = label.length > 25 ? label.slice(0, 20) + '...' : label; + const isLast = index === entries.length - 1; + return ( + + {isLast ? ( +

{label}

+ ) : ( + +

{label} >

+
+ )} +
+ ); + })} +
+ ); } \ No newline at end of file diff --git a/src/components/EventCards.jsx b/src/components/EventCards.jsx index 2f3d0ba802f6..93dc5be9976d 100644 --- a/src/components/EventCards.jsx +++ b/src/components/EventCards.jsx @@ -33,21 +33,22 @@ export const EventCardComponent = props => { export const EventCards = () => { return ( - <> +
+
{ SITE.events.slice(-4).reverse().map(event => ) }
); }; diff --git a/src/components/Events.jsx b/src/components/Events.jsx index 6acae7e39315..6161dbe070a4 100644 --- a/src/components/Events.jsx +++ b/src/components/Events.jsx @@ -5,7 +5,6 @@ import { CCardTitle, CCardContent, CCardActions } from '@cscfi/csc-ui-react'; import { EventCardComponent } from './EventCards'; -import { Breadcrumbs } from './Breadcrumbs'; //Split events to past and upcoming ones const SplitEvents = () => { @@ -244,30 +243,26 @@ export const Events = () => { }; return ( -
-
-
- -
-
- -
-
- - -
+ +
+
+ +
+
+ +
{ handleFilterChange={handleFilterChange} />
+ + ); }; diff --git a/src/components/Footer.jsx b/src/components/Footer.jsx index 0e0d49bf18af..19147003e263 100644 --- a/src/components/Footer.jsx +++ b/src/components/Footer.jsx @@ -19,7 +19,7 @@ export const Footer = props => { : <> return ( - <> + ); }; diff --git a/src/components/GetAccess.jsx b/src/components/GetAccess.jsx new file mode 100644 index 000000000000..9fecf4b3839d --- /dev/null +++ b/src/components/GetAccess.jsx @@ -0,0 +1,80 @@ +import React from "react"; +import { useEffect } from "react"; +import { prependBaseURL } from '../utils/url'; + +const ResourceCard = ({ resource }) => { + return ( + + + + ); +}; + +const ResourceList = ({ id, title, resources }) => { + return ( +
+

{title}

+
+ {resources?.map((resource, index) => ( + + ))} +
+
+ ) +} + +export const GetAccess = props => { + const quantum_resources = props?.quantum_resources + const supercomputer_resources = props?.supercomputer_resources + const emulation_resources = props?.emulation_resources + useEffect(() => { + if (window.location.hash !== "") { + const hash = window.location.hash; + const element = document.getElementById(hash.substring(1)); + if (element) { + const elementPosition = element.getBoundingClientRect().top + window.pageYOffset; + const offsetPosition = elementPosition - 100; + + window.scrollTo({ + top: offsetPosition, + behavior: 'smooth' + }); + } + } + }, []); + + return ( + +
+
+
+

Please see status of services from Status -page

+ + + + + + +
+
+ ); +}; diff --git a/src/components/Hero.jsx b/src/components/Hero.jsx index dace0e47006a..df5532218bb3 100644 --- a/src/components/Hero.jsx +++ b/src/components/Hero.jsx @@ -1,14 +1,13 @@ import React from 'react'; import '@cscfi/csc-ui-react/css/theme.css'; import { CButton, CIcon } from '@cscfi/csc-ui-react'; -import { mdiArrowRight, mdiArrowDown, mdiOpenInNew } from '@mdi/js'; +import { mdiArrowRight, mdiArrowDown } from '@mdi/js'; import { prependBaseURL, isExternal, isAnchor } from '../utils/url'; - const style = { - "--_c-button-font-size": 16, + "--_c-button-font-size": 25, "--_c-button-min-width": 0, - "--_c-button-height": "45px", + "--_c-button-height": "55px", "--_c-icon-color": "white" }; @@ -18,20 +17,40 @@ const getIconPath = href => isExternal(href) ? mdiArrowDown : mdiArrowRight -const ContentButton = props => - (window.location.href = prependBaseURL(props.href))} - > -

{props.title}

- -
+const ContentButton = props => { + const isActive = window.location.pathname === props.href; + + var styleClass = "text-white text-sm sm:text-md py-3 break-words" + if (isActive) { + styleClass = styleClass + } + + return ( +
+ (window.location.href = prependBaseURL(props.href))} + > +

{props.title}

+ +
+ (window.location.href = prependBaseURL(props.href))} + > +

{props.title}

+ +
+
+ ); +}; const Announcement = props => -
+

{props.text}

{props.link.title}
@@ -44,26 +63,28 @@ export const Hero = props => { ? : <> - return
-
+ return ( +
+
-
+
-
-
-

- {props.tagline || ''} -

-

{props.subtitle || ''}

+
+
+

+ {props.tagline || ''} +

+

{props.subtitle || ''}

+
-
-
- {announcementComponent} -
- {contentButtons} +
+ {announcementComponent} +
+ { contentButtons } +
-
-} + ) +} \ No newline at end of file diff --git a/src/components/NavigationHeader.jsx b/src/components/NavigationHeader.jsx index 5ace34ffc94a..058a0b66b52b 100644 --- a/src/components/NavigationHeader.jsx +++ b/src/components/NavigationHeader.jsx @@ -6,7 +6,7 @@ import { useJsonApi } from '../hooks/useJsonApi' import { prependBaseURL } from '../utils/url'; const style = { - "--_c-button-font-size": 12, + "--_c-button-font-size": 18, "--_c-button-min-width": 0, "--_c-button-height": "auto", "--_c-icon-color": "black" @@ -88,16 +88,17 @@ export const NavigationHeader = props => { } } if (isOpen) { //stop main content from scrolling when navigation menu open + document.body.style.overflow = 'hidden'; document.body.style.overflow = 'hidden'; document.addEventListener("mousedown", handleClickOutside); document.addEventListener("touchstart", handleClickOutside); } - else{ - document.body.style.overflow = 'visible'; + else { + document.body.style.overflow = 'visible'; } // Clean up the listeners on unmount or when isOpen changes return () => { - document.body.style.overflow = 'visible'; + document.body.style.overflow = 'visible'; document.removeEventListener("mousedown", handleClickOutside); document.removeEventListener("touchstart", handleClickOutside); }; diff --git a/src/components/ReadNext.jsx b/src/components/ReadNext.jsx new file mode 100644 index 000000000000..0e5d4da83bfa --- /dev/null +++ b/src/components/ReadNext.jsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { CAccordion, CAccordionItem, CIcon } from '@cscfi/csc-ui-react'; +import { mdiArrowRight } from '@mdi/js'; +import { BlogCardComponent } from './BlogCards'; + + +export const ReadNext = ({ title }) => { + return ( + <> +
+
+ + +
+ {SITE.publications.filter((blog) => blog.title !== title).slice(-5).reverse().map(blog => )} +
+
+
+
+
+
+

Read next:

+ {SITE.publications.filter((blog) => blog.title !== title).slice(-5).map((blog, index) => ( + + ))} + + + +
+ + ) +} \ No newline at end of file diff --git a/src/components/ReferencesAccordion.jsx b/src/components/ReferencesAccordion.jsx new file mode 100644 index 000000000000..a97962bac786 --- /dev/null +++ b/src/components/ReferencesAccordion.jsx @@ -0,0 +1,50 @@ +import React, { useEffect, useState } from 'react'; +import { CAccordion, CAccordionItem } from '@cscfi/csc-ui-react'; + +export const ReferencesAccordion = () => { + const [references, setReferences] = useState([]); + + useEffect(() => { + const observer = new MutationObserver(() => { + const header = document.getElementById('references-') || document.getElementById('references'); + if (header) { + const list = header.nextElementSibling; + if (list && list.tagName === 'OL') { + const rawHTML = list.innerHTML; + // Split and clean list items + const rawItems = rawHTML.split(/<\/li>/i) + .map(item => item.replace(/]*>/i, '').trim()) + .filter(item => item.length > 0); + + setReferences(rawItems); + + list.remove(); + header.remove(); + } + } + }); + + observer.observe(document.body, { + childList: true, + subtree: true, + }); + + return () => observer.disconnect(); + }, []); + + if (references.length === 0) return null; + + return ( + + +
    + {references.map((ref, idx) => ( +
  1. + [{idx + 1}] +
  2. + ))} +
+
+
+ ); +}; diff --git a/src/components/ServiceStatus.jsx b/src/components/ServiceStatus.jsx index cf2270e57522..65e7b7e9e71e 100644 --- a/src/components/ServiceStatus.jsx +++ b/src/components/ServiceStatus.jsx @@ -1,17 +1,12 @@ import React from 'react' import { useStatus } from '../hooks/useStatus' -import { Breadcrumbs } from './Breadcrumbs'; // import { StatusIndicator } from './StatusIndicator' export const ServiceStatus = () => { const status = useStatus('https://fiqci-backend-fiqci-workspace.2.rahtiapp.fi/healthcheck') return ( -
-
- -

@@ -59,7 +54,6 @@ export const ServiceStatus = () => {

-
); }; diff --git a/src/components/SiteSearch.jsx b/src/components/SiteSearch.jsx index a085e5a66b13..15eb91fd205b 100644 --- a/src/components/SiteSearch.jsx +++ b/src/components/SiteSearch.jsx @@ -6,7 +6,6 @@ import { CCardTitle, CCardContent, CCardActions } from '@cscfi/csc-ui-react'; -import { Breadcrumbs } from './Breadcrumbs'; const style = { "--_c-button-font-size": 14, @@ -22,21 +21,26 @@ const styleArrow = { "--_c-icon-color": "#004E84" }; -function searchContent(query, store) { - if (query.endsWith('*')) { - query = query; - } +function normalizeQuery(query) { + query = query.toLowerCase() + if (!query.trim()) return ''; // empty or whitespace-only + if (query.endsWith('*')) return query; - else { - query = query + '*'; - }; + // Optionally boost exact matches + const exactMatch = `${query}^10`; // high boost for exact match + const wildcardMatch = `${query}*`; // normal wildcard match + return `${exactMatch} ${wildcardMatch}`; +} + +function searchContent(query, store) { + const queryStr = normalizeQuery(query); const idx = lunr(function () { this.ref('key'); - this.field('title'); - this.field('content'); - this.field('type'); - this.field('tags'); + this.field('title', { boost: 10 }); + this.field('content', { boost: 2 }); + this.field('type', { boost: 5 }); + this.field('tags', { boost: 5 }); this.field('date'); this.field('link'); @@ -47,7 +51,7 @@ function searchContent(query, store) { }); }); - const results = idx.search(query); + const results = idx.search(queryStr); const categorizedResults = { general: [], @@ -55,6 +59,25 @@ function searchContent(query, store) { events: [] }; + if (results.length === 0) { + for (const key of ['blogs', 'events', 'pages']) { + for (const item of store[key]) { + if (item.title.toLowerCase().includes(query.toLowerCase())) { + categorizedResults.general.push({ + title: item.title, + url: item.url, + excerpt: item.content.substring(0, 200) + '...', + type: item.type, + tags: item.tags, + date: item.date, + link: item?.link + }); + } + } + } + } + + results.forEach(result => { const item = findItemByRef(result.ref, store); if (item) { @@ -78,6 +101,7 @@ function searchContent(query, store) { } }); + return categorizedResults; } @@ -199,7 +223,7 @@ const FilterModal = ({ isModalOpen, setIsModalOpen, filters, handleCheckboxChang return ( setIsModalOpen(event.detail)} @@ -330,10 +354,7 @@ export const SiteSearch = () => { }; return ( -
-
- -
+
diff --git a/src/layouts/home.html.jsx b/src/layouts/home.html.jsx index d411371ae571..ab509254459b 100644 --- a/src/layouts/home.html.jsx +++ b/src/layouts/home.html.jsx @@ -2,7 +2,6 @@ import React from 'react' import { createPortal } from 'react-dom' import { Hero } from '../components/Hero' -import { AboutFiqci } from '../components/AboutFiqci' import { BaseLayout } from './base.html' @@ -16,9 +15,5 @@ export const HomeLayout = props => { , document.getElementById('hero') )} - {createPortal( - , - document.getElementById('about-fiqci') - )} } diff --git a/src/layouts/page.html.jsx b/src/layouts/page.html.jsx index e425a6bedbcb..283cb80a79ab 100644 --- a/src/layouts/page.html.jsx +++ b/src/layouts/page.html.jsx @@ -3,6 +3,8 @@ import { createPortal } from 'react-dom' import { Banner } from '../components/Banner' +import { Breadcrumbs } from '../components/Breadcrumbs' + import { BaseLayout } from './base.html' @@ -16,5 +18,9 @@ export const PageLayout = props => { , document.getElementById('banner') )} + {createPortal( + , + document.getElementById('breadcrumbs') + )} } diff --git a/src/layouts/post.html.jsx b/src/layouts/post.html.jsx new file mode 100644 index 000000000000..bb0c876bfb8e --- /dev/null +++ b/src/layouts/post.html.jsx @@ -0,0 +1,50 @@ +import React from 'react' +import { createPortal } from 'react-dom' + +import { Banner } from '../components/Banner' + +import { Breadcrumbs } from '../components/Breadcrumbs' + +import { ReadNext } from '../components/ReadNext' + +import { BlogTags } from '../components/BlogTags' + +import { ReferencesAccordion } from '../components/ReferencesAccordion' + +import { BaseLayout } from './base.html' + +export const PostLayout = props => { + const title = props.title_separator + ? document.title.split(props.title_separator, 1)[0] + : "Loading..." + + const tagsData = document.getElementById('tags-data') + const tags = JSON.parse(tagsData.getAttribute('data-content')); + + const authorData = document.getElementById('author-data') + const author = JSON.parse(authorData.getAttribute('data-content')); + + return <> + + {createPortal( + , + document.getElementById('banner') + )} + {createPortal( + , + document.getElementById('breadcrumbs') + )} + {createPortal( + , + document.getElementById('read-next') + )} + {createPortal( + , + document.getElementById('tags') + )} + {createPortal( + , + document.getElementById('references-accordion') + )} + +} diff --git a/src/pages/about.md.jsx b/src/pages/about.md.jsx new file mode 100644 index 000000000000..84683344360d --- /dev/null +++ b/src/pages/about.md.jsx @@ -0,0 +1,22 @@ +import React from 'react' +import { createRoot } from 'react-dom/client' +import { createPortal } from 'react-dom' + +import { PageLayout } from '../layouts/page.html' + +import { useJsonApi } from '../hooks/useJsonApi' + + +const AboutPageView = () => { + const themeConstants = useJsonApi('api/theme/constants.json') + + return <> + + +} + +document.addEventListener('DOMContentLoaded', () => { + const root = createRoot(document.getElementById('react-root')) + + root.render() +}) diff --git a/src/pages/access.md.jsx b/src/pages/access.md.jsx new file mode 100644 index 000000000000..2570af21aded --- /dev/null +++ b/src/pages/access.md.jsx @@ -0,0 +1,28 @@ +import React from 'react' +import { createRoot } from 'react-dom/client' +import { createPortal } from 'react-dom' + +import { GetAccess } from '../components/GetAccess' + +import { PageLayout } from '../layouts/page.html' + +import { useJsonApi } from '../hooks/useJsonApi' + + +const AccessPage = () => { + const themeConstants = useJsonApi('api/theme/constants.json') + + return <> + + {createPortal( + , + document.getElementById('access') + )} + +} + +document.addEventListener('DOMContentLoaded', () => { + const root = createRoot(document.getElementById('react-root')) + + root.render() +}) diff --git a/src/pages/default.jsx b/src/pages/default.jsx index c3ea535341c5..59ce2ff293de 100644 --- a/src/pages/default.jsx +++ b/src/pages/default.jsx @@ -1,11 +1,11 @@ import React from 'react' + import { createRoot } from 'react-dom/client' import { BaseLayout } from '../layouts/base.html' import { useJsonApi } from '../hooks/useJsonApi' - const DefaultPage = () => { const themeConstants = useJsonApi('api/theme/constants.json') diff --git a/src/roots/aboutPage.jsx b/src/roots/aboutPage.jsx new file mode 100644 index 000000000000..1332b39373a1 --- /dev/null +++ b/src/roots/aboutPage.jsx @@ -0,0 +1,15 @@ +import React from 'react' +import { AboutPage } from '../components/AboutPage' +import { Banner } from '../components/Banner' +import { injectComponent } from '../utils/root' + +const component = ( + <> + + + + ); + +const rootId = 'about' + +injectComponent(component, rootId) \ No newline at end of file diff --git a/src/roots/blogView.jsx b/src/roots/blogView.jsx new file mode 100644 index 000000000000..15ed0031b2d3 --- /dev/null +++ b/src/roots/blogView.jsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { BlogView } from '../components/BlogView'; +import { Banner } from '../components/Banner'; +import { injectComponent } from '../utils/root'; + + +const component = ( + <> + + + +) +injectComponent(component, 'blog-view'); + diff --git a/src/roots/getAccess.jsx b/src/roots/getAccess.jsx new file mode 100644 index 000000000000..146fb2e73941 --- /dev/null +++ b/src/roots/getAccess.jsx @@ -0,0 +1,15 @@ +import React from 'react' +import { GetAccess } from '../components/GetAccess' +import { Banner } from '../components/Banner' +import { injectComponent } from '../utils/root' + +const component = ( + <> + + + + ); + +const rootId = 'access' + +injectComponent(component, rootId) \ No newline at end of file diff --git a/src/stylesheets/main.css b/src/stylesheets/main.css index b5c61c956711..bd6213e1dfe6 100644 --- a/src/stylesheets/main.css +++ b/src/stylesheets/main.css @@ -1,3 +1,3 @@ @tailwind base; @tailwind components; -@tailwind utilities; +@tailwind utilities; \ No newline at end of file diff --git a/src/views/post.jsx b/src/views/post.jsx new file mode 100644 index 000000000000..c5de5bf38fee --- /dev/null +++ b/src/views/post.jsx @@ -0,0 +1,22 @@ +import React from 'react' + +import { createRoot } from 'react-dom/client' + +import { PostLayout } from '../layouts/post.html' + +import { useJsonApi } from '../hooks/useJsonApi' + +const BlogViewPage = () => { + const themeConstants = useJsonApi('api/theme/constants.json') + return ( + <> + + + ) +} + +document.addEventListener('DOMContentLoaded', () => { + const root = createRoot(document.getElementById('react-root')) + + root.render() +}) diff --git a/webpack.config.js b/webpack.config.js index 433c3a078534..35a7b5d2af7d 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -12,17 +12,24 @@ const JEKYLL_CONFIG_FNAME = process.env.npm_package_config_jekyll_webpackConfigFilename; const OUTPUT_DIR = process.env.npm_package_config_webpack_outputDir; +const reactPageSources = REACT_PAGES_DIR.split(",").map((dir) => path.resolve(__dirname, dir.trim())); const stylesheetsDirpath = path.resolve(__dirname, TAILWINDCSS_INPUT_DIR); -const reactPageSources = path.resolve(__dirname, REACT_PAGES_DIR); const outputDirpath = path.resolve(__dirname, OUTPUT_DIR); const jekyllConfigFilepath = path.resolve(__dirname, JEKYLL_CONFIG_FNAME); + const entryFiles = {}; -fs.readdirSync(reactPageSources).forEach((file) => { - if (file.endsWith(".jsx")) { - const name = path.parse(file).name; // Use the file name (without extension) as the entry name - entryFiles[name] = path.resolve(__dirname, REACT_PAGES_DIR, file); - } + +reactPageSources.forEach((dir) => { + const absReactDir = path.resolve(__dirname, dir); + if (!fs.existsSync(absReactDir)) return; + + fs.readdirSync(absReactDir).forEach((file) => { + if (file.endsWith(".jsx")) { + const name = path.parse(file).name; // Use the file name (without extension) as the entry name + entryFiles[name] = path.resolve(__dirname, absReactDir, file); + } + }); }); const cssFilenames = fs