+
{{ content }}
diff --git a/content/index.md b/content/index.md
index fcb55f7a7a72..7ae62a9cdca9 100644
--- a/content/index.md
+++ b/content/index.md
@@ -1,12 +1,11 @@
---
+title: Welcome
layout: home
-react_source_files:
- - accessCards.js
- - blogCards.js
- - eventCards.js
- - aboutFiqci.js
-
+react: true
---
-{%- include react/root.html id='access-cards' -%}
-{%- include react/root.html id='blog-cards' -%}
-{%- include react/root.html id='event-cards' -%}
+
+{% include react/section-root.html id='access-cards' heading='Get access' %}
+
+{% include react/section-root.html id='blog-cards' heading='Blogs and instructions' %}
+
+{% include react/section-root.html id='event-cards' heading='Events' %}
diff --git a/content/pages/events.md b/content/pages/events.md
index 7fbf46c5fe2d..8552ec3e9a67 100644
--- a/content/pages/events.md
+++ b/content/pages/events.md
@@ -2,8 +2,7 @@
layout: page
title: Events
subtitle: Upcoming and past events with connection to FiQCI
-react_source_files:
- - events.js
+react: true
---
{%- include react/root.html id='events' -%}
diff --git a/content/pages/publications.md b/content/pages/publications.md
index b016fb3b9441..f3b6c80117a1 100644
--- a/content/pages/publications.md
+++ b/content/pages/publications.md
@@ -1,9 +1,8 @@
---
-layout: page
-title: Posts and publications
+title: Blogs and instructions
subtitle: Blog posts, publications, and other material of interest
-react_source_files:
- - blogs.js
+layout: page
+react: true
---
{%- include react/root.html id='blogs' -%}
diff --git a/content/pages/search.md b/content/pages/search.md
index e1fe74b1f6ee..d0bb72ad623a 100644
--- a/content/pages/search.md
+++ b/content/pages/search.md
@@ -1,8 +1,8 @@
---
-layout: page
+layout: base
title: Search Results
-react_source_files:
- - searchPage.js
+react: true
---
-
-{%- include react/root.html id='search-page' -%}
\ No newline at end of file
+
+
+{%- include react/root.html id='site-search' -%}
diff --git a/content/pages/status.md b/content/pages/status.md
index 6079f878ac96..3606e39390d4 100644
--- a/content/pages/status.md
+++ b/content/pages/status.md
@@ -1,9 +1,8 @@
---
-layout: page
title: Status
subtitle: View the status of the Quantum Connections
-react_source_files:
- - status.js
+layout: page
+react: true
---
{%- include react/root.html id='service-status' -%}
diff --git a/content/properties.css.liquid b/content/properties.css.liquid
new file mode 100644
index 000000000000..6ca655ab6011
--- /dev/null
+++ b/content/properties.css.liquid
@@ -0,0 +1,9 @@
+---
+permalink: properties.css
+---
+
+@layer components {
+ :root {
+ --fiqci-banner-image: url({{ '/assets/images/FiQCI-banner.jpg' | absolute_url }});
+ }
+}
diff --git a/content/site.js b/content/site.js.liquid
similarity index 72%
rename from content/site.js
rename to content/site.js.liquid
index 9a6a2fe57d21..ebdccf3bdabd 100644
--- a/content/site.js
+++ b/content/site.js.liquid
@@ -1,22 +1,26 @@
---
+permalink: site.js
---
+
{%- assign values = site.data.site-constants -%}
+{%- assign deployment = site-%}
{%- capture constants -%}
{
- "logo": "{{ values.logo | relative_url }}",
"baseUrl": "{{ site.baseurl }}",
+ "feedbackEmail": "{{ values.feedback_email }}",
+ "images": {
+ "logo": "{{ values.logo | absolute_url }}",
+ "funderLogosPath": "{{ values.funder-logos | absolute_url }}",
+ "footerIconsPath": "{{ values.footer-icons | absolute_url }}"
+ },
"topNav": [
{ "title": "Home", "href": "{{ site.baseurl }}", "key": 0 },
- { "title": "Blogs and instructions", "href": "{{ '/publications' | relative_url }}", "key": 1 },
- { "title": "Status", "href": "{{ '/status' | relative_url }}", "key": 2 },
- { "title": "Events", "href": "{{ '/events' | relative_url }}", "key": 3 },
- { "title": "Search", "href": "{{ '/search' | relative_url }}", "key": 4 }
- ],
- "cardNav": [
- { "title": "How to get access", "href": "{{ '/access' | relative_url }}", "key": 5 },
- { "title": "Blogs and instructions", "href": "{{ '/publications' | relative_url }}", "key": 6 },
- { "title": "About FiQCI", "href": "{{ '/about' | relative_url }}", "key": 7 }
+ { "title": "Get access", "href": "{{ '/access' | absolute_url }}", "key": 1 },
+ { "title": "Blogs and instructions", "href": "{{ '/publications' | absolute_url }}", "key": 2 },
+ { "title": "Status", "href": "{{ '/status' | absolute_url }}", "key": 3 },
+ { "title": "Events", "href": "{{ '/events' | absolute_url }}", "key": 4 },
+ { "title": "Search", "href": "{{ '/search' | absolute_url }}", "key": 5 }
]
}
{%- endcapture -%}
@@ -28,9 +32,9 @@
"key": "{{ forloop.index }}",
"type": "{{ publication.type | default: 'News' }}",
"title": "{{ publication.title }}",
- "url": "{{ publication.url | relative_url }}",
+ "url": "{{ publication.url | absolute_url }}",
"date": "{{ publication.date | date: '%-d.%-m.%Y' }}",
- "teaser": "{{publication.header.teaser | relative_url}}",
+ "teaser": "{{ publication.header.teaser | absolute_url }}",
"filters": {
{%- for category in publication.filters %}
{%- if category[0] == "Theme" -%}
@@ -57,7 +61,7 @@
"key": "{{ forloop.index }}",
"type": "Event",
"title": "{{ event_post.title }}",
- "url": "{{ event_post.link | relative_url }}",
+ "url": "{{ event_post.link | uri_escape }}",
"date": "{{ event_post.date | date: '%-d.%-m.%Y' }}",
"content": {{ event_post.content | strip_html | strip_newlines | jsonify }},
"filters": {
@@ -80,6 +84,7 @@
{%- endcapture -%}
const SITE = {
+ deployment: { baseURL: "{{ site.baseurl }}" },
constants: JSON.parse(String.raw`{{- constants -}}`),
publications: JSON.parse(String.raw`{{- publications -}}`),
events: JSON.parse(String.raw`{{- events -}}`),
diff --git a/content/site.json.liquid b/content/site.json.liquid
new file mode 100644
index 000000000000..292d9fbfa011
--- /dev/null
+++ b/content/site.json.liquid
@@ -0,0 +1,5 @@
+---
+permalink: api/site.json
+---
+
+{{ site.data.site-constants | jsonify }}
diff --git a/content/store.js b/content/store.js.liquid
similarity index 98%
rename from content/store.js
rename to content/store.js.liquid
index b516c5834cb6..eb158d051588 100644
--- a/content/store.js
+++ b/content/store.js.liquid
@@ -1,4 +1,5 @@
---
+permalink: store.js
---
{%- capture blogs -%}
diff --git a/package.json b/package.json
index e404c228060d..acdff23819ea 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
},
"webpack": {
"outputDir": "./dist",
- "reactRootsDir": "./src/roots"
+ "reactPagesDir": "./src/pages"
},
"tailwindcss": {
"inputDir": "./src/stylesheets"
@@ -25,7 +25,7 @@
"jekyll:serve": "npm run-script jekyll -- serve --config ${npm_package_config_jekyll_configFilename},${npm_package_config_jekyll_webpackConfigFilename}",
"jekyll:build": "npm run-script jekyll -- build --config ${npm_package_config_jekyll_configFilename},${npm_package_config_jekyll_webpackConfigFilename}",
"clean": "npm run-script jekyll -- clean --config ${npm_package_config_jekyll_configFilename},${npm_package_config_jekyll_webpackConfigFilename} && rm ${npm_package_config_jekyll_webpackConfigFilename}",
- "watch": "npx concurrently --kill-others --prefix-colors ${npm_package_config_conc_colors} --passthrough-arguments 'npm:tailwindcss -- {1}' 'npm:webpack -- --mode=development {1}' 'npm:jekyll:serve -- --livereload' -- --watch",
+ "watch": "npx concurrently --kill-others --prefix-colors ${npm_package_config_conc_colors} --passthrough-arguments 'npm:tailwindcss -- {1}' 'npm:webpack -- --mode=development {1}' 'npm:jekyll:serve -- --livereload --baseurl /dev/' -- --watch",
"build": "npm run-script tailwindcss && npm run-script webpack -- --mode=production && npm run-script jekyll:build",
"start": "npm run-script tailwindcss && npm run-script webpack -- --mode=development && npm run-script jekyll:serve"
},
diff --git a/src/components/AboutFiqci.jsx b/src/components/AboutFiqci.jsx
index 5981910627a6..8cd5bb60de29 100644
--- a/src/components/AboutFiqci.jsx
+++ b/src/components/AboutFiqci.jsx
@@ -9,7 +9,7 @@ export const AboutFiqci = () => {
-
About Fiqci
+ About FiQCI
diff --git a/src/components/AccessCards.jsx b/src/components/AccessCards.jsx
index 8ab23f4b5c5d..5edf92e05661 100644
--- a/src/components/AccessCards.jsx
+++ b/src/components/AccessCards.jsx
@@ -2,100 +2,56 @@ import React from 'react';
import '@cscfi/csc-ui-react/css/theme.css';
import { CCard, CIcon, CCardContent } from '@cscfi/csc-ui-react';
import { mdiArrowRight, mdiOpenInNew } from '@mdi/js';
+import { prependBaseURL, isExternal } from '../utils/url';
-const AccessCardComponent = ({ title, teaser, description, links }) => {
- return (
-
+import { useConstants } from '../hooks/useConstants';
+
+const AccessCardComponent = ({ title, href, teaser, description, links }) =>
+
-
- {title}
-
-
- {description}
-
-
-
-
- );
- };
-
+
+ {title}
+
-export const AccessCard = () => {
- return (
-
-
-
Get access
-
+
{description}
-
-
-
-
+
-
+
+
+
+
+export const AccessCards = () => {
+ const siteConstants = useConstants("api/site.json")
+ const cards = siteConstants["access-cards"]
+ const accessCardComponents =
+ cards?.map(card => (
))
+
+ return <>
+
+ {accessCardComponents}
+
+
Other quantum resources will continuously be added to the FiQCI infrastructure.
-
-
-
-
-
+ href="#"
+ className="text-sky-800 hover:underline font-bold"
+ >
+
+
- );
+ >
};
diff --git a/src/components/BlogCards.jsx b/src/components/BlogCards.jsx
index fde951a7491e..9292a32e371b 100644
--- a/src/components/BlogCards.jsx
+++ b/src/components/BlogCards.jsx
@@ -3,7 +3,7 @@ import '@cscfi/csc-ui-react/css/theme.css';
import { CCard, CIcon, CCardContent } from '@cscfi/csc-ui-react';
import { mdiArrowRight } from '@mdi/js';
-const BlogCardComponent = props => {
+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 */}
@@ -25,15 +25,9 @@ const BlogCardComponent = props => {
);
};
-
-
-const BlogCard = () => {
+export const BlogCards = () => {
return (
-
-
-
Blogs and instructions
-
-
+ <>
{ SITE.publications.slice(-5).reverse().map(blog => ) }
@@ -48,8 +42,6 @@ const BlogCard = () => {
-
+ >
);
};
-
-export { BlogCard, BlogCardComponent }
\ No newline at end of file
diff --git a/src/components/EventCards.jsx b/src/components/EventCards.jsx
index 574cee3b4c4d..2f3d0ba802f6 100644
--- a/src/components/EventCards.jsx
+++ b/src/components/EventCards.jsx
@@ -3,8 +3,7 @@ import '@cscfi/csc-ui-react/css/theme.css';
import { CCard, CIcon, CCardContent } from '@cscfi/csc-ui-react';
import { mdiArrowRight, mdiOpenInNew } from '@mdi/js';
-
-const EventCardComponent = props => {
+export const EventCardComponent = props => {
return (
{/* Adjusted card width */}
@@ -32,13 +31,9 @@ const EventCardComponent = props => {
-const EventCard = () => {
+export const EventCards = () => {
return (
-
-
-
Events
-
-
+ <>
{ SITE.events.slice(-4).reverse().map(event => ) }
@@ -46,15 +41,13 @@ const EventCard = () => {
+ >
-
+ >
);
};
-
-export { EventCard, EventCardComponent }
\ No newline at end of file
diff --git a/src/components/Footer.jsx b/src/components/Footer.jsx
index 1f7a4adce8f0..221be2c7c649 100644
--- a/src/components/Footer.jsx
+++ b/src/components/Footer.jsx
@@ -1,32 +1,41 @@
import React from 'react';
export const Footer = () => {
+ const {
+ baseUrl,
+ feedbackEmail,
+ images: {
+ footerIconsPath,
+ funderLogosPath
+ }
+ } = SITE.constants
+
return (
-
+ <>
@@ -37,22 +46,18 @@ export const Footer = () => {
© 2024 The FiQCI Consortium. Powered by{" "}
Jekyll
- {" "}
- &{" "}
-
- Minimal Mistakes
- .
+
-
+ >
);
};
diff --git a/src/components/Hero.jsx b/src/components/Hero.jsx
new file mode 100644
index 000000000000..dace0e47006a
--- /dev/null
+++ b/src/components/Hero.jsx
@@ -0,0 +1,69 @@
+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 { prependBaseURL, isExternal, isAnchor } from '../utils/url';
+
+
+const style = {
+ "--_c-button-font-size": 16,
+ "--_c-button-min-width": 0,
+ "--_c-button-height": "45px",
+ "--_c-icon-color": "white"
+};
+
+const getIconPath = href => isExternal(href)
+ ? mdiOpenInNew
+ : isAnchor(href)
+ ? mdiArrowDown
+ : mdiArrowRight
+
+const ContentButton = props =>
+
(window.location.href = prependBaseURL(props.href))}
+ >
+ {props.title}
+
+
+
+const Announcement = props =>
+
+
+export const Hero = props => {
+ const contentButtons =
+ props.buttons?.map(button =>
)
+
+ const announcementComponent = typeof props.announcement !== 'undefined'
+ ?
+ : <>>
+
+ return
+
+
+
+
+
+
+
+ {props.tagline || ''}
+
+
{props.subtitle || ''}
+
+
+
+
+ {announcementComponent}
+
+ {contentButtons}
+
+
+
+
+}
diff --git a/src/components/Home.jsx b/src/components/Home.jsx
deleted file mode 100644
index ad647dd753de..000000000000
--- a/src/components/Home.jsx
+++ /dev/null
@@ -1,72 +0,0 @@
-import React from 'react';
-import '@cscfi/csc-ui-react/css/theme.css';
-import { CButton, CIcon } from '@cscfi/csc-ui-react';
-import { mdiArrowRight, mdiArrowDown } from '@mdi/js';
-
-const style = {
- "--_c-button-font-size": 16,
- "--_c-button-min-width": 0,
- "--_c-button-height": "45px",
- "--_c-icon-color": "white"
-};
-
-const ContentButton = props => {
- const isActive = window.location.pathname === props.href;
-
- var styleClass = "text-white text-md py-3"
- if (isActive) {
- styleClass = styleClass
- }
-
- return (
-
(window.location.href = props.href)}
- >
- {props.title}
-
-
- );
-};
-
-export const Home = () => {
- const test_lg = 500;
- const test = 'flex flex-col justify-evenly z-2 bg-orange-200 min-h-[100px] pl-[30px]'
- const nav = SITE.constants.cardNav
- const contentButtons = [
- ["How to get access", mdiArrowDown],
- ["Blogs and instructions", mdiArrowRight],
- ["About FiQCI", mdiArrowRight],
- ].map(([title, icon]) => [nav.find(page => page.title === title), icon])
- .map(([page, icon]) =>
)
-
- return (
-
-
-
-
-
-
-
-
- Making the power of quantum computing accessible
-
-
FiQCI - Finnish quantum-computing infrastructure
-
-
-
-
-
-
- { contentButtons }
-
-
-
-
- )
-}
\ No newline at end of file
diff --git a/src/components/NavigationHeader.jsx b/src/components/NavigationHeader.jsx
index bb4669ad6229..2ad45f4c130c 100644
--- a/src/components/NavigationHeader.jsx
+++ b/src/components/NavigationHeader.jsx
@@ -2,6 +2,7 @@ import React, { useState, useRef, useEffect } from 'react';
import '@cscfi/csc-ui-react/css/theme.css';
import { CButton, CIcon } from '@cscfi/csc-ui-react';
import { mdiMagnify, mdiMenu } from '@mdi/js';
+import { prependBaseURL } from '../utils/url';
const style = {
"--_c-button-font-size": 12,
@@ -85,9 +86,9 @@ export const NavigationHeader = () => {
-
+
diff --git a/src/components/SearchPage.jsx b/src/components/SiteSearch.jsx
similarity index 99%
rename from src/components/SearchPage.jsx
rename to src/components/SiteSearch.jsx
index b34e5b66eb23..a085e5a66b13 100644
--- a/src/components/SearchPage.jsx
+++ b/src/components/SiteSearch.jsx
@@ -7,7 +7,6 @@ import {
} from '@cscfi/csc-ui-react';
import { Breadcrumbs } from './Breadcrumbs';
-import { use } from 'react';
const style = {
"--_c-button-font-size": 14,
@@ -218,7 +217,7 @@ const FilterModal = ({ isModalOpen, setIsModalOpen, filters, handleCheckboxChang
)
};
-export const SearchPage = () => {
+export const SiteSearch = () => {
const [isModalOpen, setIsModalOpen] = useState(false); //modal control
const [results, setResults] = useState({ general: [], blogs: [], events: [] });
diff --git a/src/components/layouts/base.html.jsx b/src/components/layouts/base.html.jsx
new file mode 100644
index 000000000000..24abe14fdd15
--- /dev/null
+++ b/src/components/layouts/base.html.jsx
@@ -0,0 +1,30 @@
+import React from 'react'
+import { createPortal } from 'react-dom'
+
+import { NavigationHeader } from '../NavigationHeader'
+import { Footer } from '../Footer'
+
+import { useMatomo } from '../../hooks/useMatomo'
+
+
+const Analytics = () => {
+ const url = process.env.MATOMO_URL
+ const id = process.env.MATOMO_TAG_MANAGER_CONTAINER
+
+ useMatomo(url, id)
+
+ return <>>
+}
+
+export const BaseLayout = props =>
+ <>
+
+ {createPortal(
+ ,
+ document.getElementById('navigation-header')
+ )}
+ {createPortal(
+ ,
+ document.getElementById('footer')
+ )}
+ >
diff --git a/src/components/layouts/home.html.jsx b/src/components/layouts/home.html.jsx
new file mode 100644
index 000000000000..7b2c560cbdcc
--- /dev/null
+++ b/src/components/layouts/home.html.jsx
@@ -0,0 +1,24 @@
+import React from 'react'
+import { createPortal } from 'react-dom'
+
+import { Hero } from '../Hero'
+import { AboutFiqci } from '../AboutFiqci'
+
+import { BaseLayout } from './base.html'
+
+
+export const HomeLayout = props => {
+ const heroConstants = props.hero
+
+ return <>
+
+ {createPortal(
+ ,
+ document.getElementById('hero')
+ )}
+ {createPortal(
+ ,
+ document.getElementById('about-fiqci')
+ )}
+ >
+}
diff --git a/src/components/layouts/page.html.jsx b/src/components/layouts/page.html.jsx
new file mode 100644
index 000000000000..e72b907be484
--- /dev/null
+++ b/src/components/layouts/page.html.jsx
@@ -0,0 +1,20 @@
+import React from 'react'
+import { createPortal } from 'react-dom'
+
+import { Banner } from '../Banner'
+
+import { BaseLayout } from './base.html'
+
+
+export const PageLayout = props => {
+ const title = props.title_separator
+ ? document.title.split(props.title_separator, 1)[0]
+ : "Loading..."
+ return <>
+
+ {createPortal(
+ ,
+ document.getElementById('banner')
+ )}
+ >
+}
diff --git a/src/hooks/useConstants.jsx b/src/hooks/useConstants.jsx
new file mode 100644
index 000000000000..c17638fc0d96
--- /dev/null
+++ b/src/hooks/useConstants.jsx
@@ -0,0 +1,25 @@
+import { useEffect, useState } from 'react'
+import { isExternal, prependBaseURL } from '../utils/url'
+
+export const useConstants = constantsPath => {
+ const [constants, setConstants] = useState({})
+
+ useEffect(() => {
+ let ignore = false
+
+ const fetchConstants = async path => {
+ const response = await fetch(path)
+ const result = await response.json()
+
+ if (!ignore) {
+ setConstants(result)
+ }
+ }
+
+ fetchConstants(prependBaseURL(constantsPath))
+
+ return () => { ignore = true }
+ }, [constantsPath])
+
+ return constants
+}
diff --git a/src/hooks/useMatomo.jsx b/src/hooks/useMatomo.jsx
new file mode 100644
index 000000000000..d19bde33ca21
--- /dev/null
+++ b/src/hooks/useMatomo.jsx
@@ -0,0 +1,14 @@
+import { useEffect } from 'react'
+
+export const useMatomo = (matomoURL, MTMContainerId) => {
+ if ([matomoURL, MTMContainerId].every(elem => typeof elem !== 'undefined')) {
+ const matomoSrc = URL.parse(`/js/container_${MTMContainerId}.js`, `https://${matomoURL}`)
+
+ useEffect(() => {
+ var _mtm = window._mtm = window._mtm || [];
+ _mtm.push({ 'mtm.startTime': (new Date().getTime()), 'event': 'mtm.Start' });
+ var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
+ g.async = true; g.src = matomoSrc; s.parentNode.insertBefore(g, s);
+ }, [])
+ }
+}
diff --git a/src/pages/default.jsx b/src/pages/default.jsx
new file mode 100644
index 000000000000..c6bd55f96fd4
--- /dev/null
+++ b/src/pages/default.jsx
@@ -0,0 +1,21 @@
+import React from 'react'
+import { createRoot } from 'react-dom/client'
+
+import { BaseLayout } from '../components/layouts/base.html'
+
+import { useConstants } from '../hooks/useConstants'
+
+
+const DefaultPage = () => {
+ const siteConstants = useConstants('api/site.json')
+
+ return <>
+
+ >
+}
+
+document.addEventListener('DOMContentLoaded', () => {
+ const root = createRoot(document.getElementById('react-root'))
+
+ root.render( )
+})
diff --git a/src/pages/events.md.jsx b/src/pages/events.md.jsx
new file mode 100644
index 000000000000..89e4ba33caaa
--- /dev/null
+++ b/src/pages/events.md.jsx
@@ -0,0 +1,28 @@
+import React from 'react'
+import { createRoot } from 'react-dom/client'
+import { createPortal } from 'react-dom'
+
+import { Events } from '../components/Events'
+
+import { PageLayout } from '../components/layouts/page.html'
+
+import { useConstants } from '../hooks/useConstants'
+
+
+const EventsPage = () => {
+ const siteConstants = useConstants('api/site.json')
+
+ return <>
+
+ {createPortal(
+ ,
+ document.getElementById('events')
+ )}
+ >
+}
+
+document.addEventListener('DOMContentLoaded', () => {
+ const root = createRoot(document.getElementById('react-root'))
+
+ root.render( )
+})
diff --git a/src/pages/index.md.jsx b/src/pages/index.md.jsx
new file mode 100644
index 000000000000..2dba711618de
--- /dev/null
+++ b/src/pages/index.md.jsx
@@ -0,0 +1,39 @@
+import React from 'react'
+import { createRoot } from 'react-dom/client'
+import { createPortal } from 'react-dom'
+
+import { AccessCards } from '../components/AccessCards'
+import { BlogCards } from '../components/BlogCards'
+import { EventCards } from '../components/EventCards'
+
+import { HomeLayout } from '../components/layouts/home.html'
+
+import { useConstants } from '../hooks/useConstants'
+
+
+const HomePage = () => {
+ const siteConstants = useConstants('api/site.json')
+ const accessConstants = siteConstants['access-cards']
+
+ return <>
+
+ {createPortal(
+ ,
+ document.getElementById('access-cards')
+ )}
+ {createPortal(
+ ,
+ document.getElementById('blog-cards')
+ )}
+ {createPortal(
+ ,
+ document.getElementById('event-cards')
+ )}
+ >
+}
+
+document.addEventListener('DOMContentLoaded', () => {
+ const root = createRoot(document.getElementById('react-root'))
+
+ root.render( )
+})
diff --git a/src/pages/publications.md.jsx b/src/pages/publications.md.jsx
new file mode 100644
index 000000000000..8d5ed9d2c90f
--- /dev/null
+++ b/src/pages/publications.md.jsx
@@ -0,0 +1,28 @@
+import React from 'react'
+import { createRoot } from 'react-dom/client'
+import { createPortal } from 'react-dom'
+
+import { Blogs } from '../components/Blogs'
+
+import { PageLayout } from '../components/layouts/page.html'
+
+import { useConstants } from '../hooks/useConstants'
+
+
+const BlogsPage = () => {
+ const siteConstants = useConstants('api/site.json')
+
+ return <>
+
+ {createPortal(
+ ,
+ document.getElementById('blogs')
+ )}
+ >
+}
+
+document.addEventListener('DOMContentLoaded', () => {
+ const root = createRoot(document.getElementById('react-root'))
+
+ root.render( )
+})
diff --git a/src/pages/search.md.jsx b/src/pages/search.md.jsx
new file mode 100644
index 000000000000..4a62c563245b
--- /dev/null
+++ b/src/pages/search.md.jsx
@@ -0,0 +1,28 @@
+import React from 'react'
+import { createRoot } from 'react-dom/client'
+import { createPortal } from 'react-dom'
+
+import { SiteSearch } from '../components/SiteSearch'
+
+import { BaseLayout } from '../components/layouts/base.html'
+
+import { useConstants } from '../hooks/useConstants'
+
+
+const SearchPage = () => {
+ const siteConstants = useConstants('api/site.json')
+
+ return <>
+
+ {createPortal(
+ ,
+ document.getElementById('site-search')
+ )}
+ >
+}
+
+document.addEventListener('DOMContentLoaded', () => {
+ const root = createRoot(document.getElementById('react-root'))
+
+ root.render( )
+})
diff --git a/src/pages/status.md.jsx b/src/pages/status.md.jsx
new file mode 100644
index 000000000000..c3fd60a35220
--- /dev/null
+++ b/src/pages/status.md.jsx
@@ -0,0 +1,28 @@
+import React from 'react'
+import { createRoot } from 'react-dom/client'
+import { createPortal } from 'react-dom'
+
+import { ServiceStatus } from '../components/ServiceStatus'
+
+import { PageLayout } from '../components/layouts/page.html'
+
+import { useConstants } from '../hooks/useConstants'
+
+
+const StatusPage = () => {
+ const siteConstants = useConstants('api/site.json')
+
+ return <>
+
+ {createPortal(
+ ,
+ document.getElementById('service-status')
+ )}
+ >
+}
+
+document.addEventListener('DOMContentLoaded', () => {
+ const root = createRoot(document.getElementById('react-root'))
+
+ root.render( )
+})
diff --git a/src/roots/aboutFiqci.jsx b/src/roots/aboutFiqci.jsx
deleted file mode 100644
index a1b484de06b2..000000000000
--- a/src/roots/aboutFiqci.jsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from 'react'
-import { AboutFiqci } from '../components/AboutFiqci'
-import { injectComponent } from '../utils/root'
-
-const component =
-const rootId = 'about-fiqci'
-
-injectComponent(component, rootId)
\ No newline at end of file
diff --git a/src/roots/accessCards.jsx b/src/roots/accessCards.jsx
deleted file mode 100644
index 28232b561235..000000000000
--- a/src/roots/accessCards.jsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from 'react'
-import { AccessCard } from '../components/AccessCards'
-import { injectComponent } from '../utils/root'
-
-const component =
-const rootId = 'access-cards'
-
-injectComponent(component, rootId)
\ No newline at end of file
diff --git a/src/roots/blogCards.jsx b/src/roots/blogCards.jsx
deleted file mode 100644
index c7bf214f8599..000000000000
--- a/src/roots/blogCards.jsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from 'react'
-import { BlogCard } from '../components/BlogCards'
-import { injectComponent } from '../utils/root'
-
-const component =
-const rootId = 'blog-cards'
-
-injectComponent(component, rootId)
diff --git a/src/roots/blogs.jsx b/src/roots/blogs.jsx
deleted file mode 100644
index 86ab2982f8e3..000000000000
--- a/src/roots/blogs.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react'
-import { Blogs } from '../components/Blogs'
-import { Banner } from '../components/Banner'
-import { injectComponent } from '../utils/root'
-
-const component = (
- <>
-
-
- >)
-const rootId = 'blogs'
-
-injectComponent(component, rootId)
diff --git a/src/roots/eventCards.jsx b/src/roots/eventCards.jsx
deleted file mode 100644
index b0486acf6bed..000000000000
--- a/src/roots/eventCards.jsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from 'react'
-import { EventCard } from '../components/EventCards'
-import { injectComponent } from '../utils/root'
-
-const component =
-const rootId = 'event-cards'
-
-injectComponent(component, rootId)
diff --git a/src/roots/events.jsx b/src/roots/events.jsx
deleted file mode 100644
index 197e2dcad5fc..000000000000
--- a/src/roots/events.jsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react'
-import { Events } from '../components/Events'
-import { Banner } from '../components/Banner'
-import { injectComponent } from '../utils/root'
-
-const component = (
- <>
-
-
- >
- );
-
-const rootId = 'events'
-
-injectComponent(component, rootId)
diff --git a/src/roots/footer.jsx b/src/roots/footer.jsx
deleted file mode 100644
index 3dd4303dba61..000000000000
--- a/src/roots/footer.jsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from 'react'
-import { Footer } from '../components/Footer'
-import { injectComponent } from '../utils/root'
-
-const component =
-const rootId = 'footer'
-
-injectComponent(component, rootId)
diff --git a/src/roots/home.jsx b/src/roots/home.jsx
deleted file mode 100644
index 822d05262131..000000000000
--- a/src/roots/home.jsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from 'react'
-import { Home } from '../components/Home'
-import { injectComponent } from '../utils/root'
-
-const component =
-const rootId = 'home'
-
-injectComponent(component, rootId)
diff --git a/src/roots/navigation.jsx b/src/roots/navigation.jsx
deleted file mode 100644
index 97742f4f07b2..000000000000
--- a/src/roots/navigation.jsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from 'react'
-import { NavigationHeader } from '../components/NavigationHeader'
-import { injectComponent } from '../utils/root'
-
-const component =
-const rootId = 'navigation-header'
-
-injectComponent(component, rootId)
diff --git a/src/roots/searchPage.jsx b/src/roots/searchPage.jsx
deleted file mode 100644
index 44ef6b51daa8..000000000000
--- a/src/roots/searchPage.jsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from 'react'
-import { SearchPage } from '../components/SearchPage'
-import { injectComponent } from '../utils/root'
-
-const component =
-const rootId = 'search-page'
-
-injectComponent(component, rootId)
diff --git a/src/roots/status.jsx b/src/roots/status.jsx
deleted file mode 100644
index 86fc999108ba..000000000000
--- a/src/roots/status.jsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react'
-import { ServiceStatus } from '../components/ServiceStatus'
-import { Banner } from '../components/Banner'
-import { injectComponent } from '../utils/root'
-
-const component = (
- <>
-
-
- >
- );
-const rootId = 'service-status'
-
-injectComponent(component, rootId)
diff --git a/src/utils/root.js b/src/utils/root.js
deleted file mode 100644
index af3418fab950..000000000000
--- a/src/utils/root.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { createRoot } from 'react-dom/client'
-
-export const injectComponent = (component, rootId) => {
- document.addEventListener('DOMContentLoaded', () => {
- const rootElement = document.getElementById(rootId)
-
- if (rootElement instanceof Element) {
- const root = createRoot(rootElement)
- root.render(component)
- }
- })
-}
diff --git a/src/utils/url.js b/src/utils/url.js
new file mode 100644
index 000000000000..b9c26ddc06ed
--- /dev/null
+++ b/src/utils/url.js
@@ -0,0 +1,25 @@
+const prependToPathname = (href, value) => {
+ const url = URL.parse(href, window.location.origin)
+ const basepath = URL.parse(value, window.location.origin).pathname
+ const path = basepath.concat(url.pathname)
+
+ return new URL(path, window.location.origin).pathname
+}
+
+export const isExternal = href =>
+ URL.parse(href, window.location.origin).origin !== window.location.origin
+
+export const isAnchor = href => {
+ if (isExternal(href)) return false
+
+ const url = URL.parse(href, window.location.origin)
+ const path = prependToPathname(href, SITE.deployment.baseURL)
+
+ return !!url.hash && window.location.pathname === path
+}
+
+export const prependBaseURL = href => {
+ if (isExternal(href) || isAnchor(href)) return href
+
+ return prependToPathname(href, SITE.deployment.baseURL)
+}
diff --git a/tailwind.config.js b/tailwind.config.js
index 797226908d47..185c02dc1656 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,13 +1,18 @@
/** @type {import('tailwindcss').Config} */
+const defaultTheme = require('tailwindcss/defaultTheme')
+
module.exports = {
content: {
files: ["./src/**/*.{js,jsx}", "./content/**/*.{md,html}"],
},
theme: {
extend: {
+ fontFamily: {
+ 'sans': ['"Inter"', ...defaultTheme.fontFamily.sans],
+ },
backgroundImage: {
- 'fiqci': "url('/assets/images/FiQCI-banner.jpg')",
+ 'fiqci': "var(--fiqci-banner-image)",
},
},
},
diff --git a/webpack.config.js b/webpack.config.js
index 5e17b30c85f7..433c3a078534 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,27 +1,27 @@
+const webpack = require("webpack");
const path = require("path");
const fs = require("fs");
-
const yaml = require("yaml");
const TAILWINDCSS_INPUT_DIR =
process.env.npm_package_config_tailwindcss_inputDir;
-const REACT_ROOTS_DIR = process.env.npm_package_config_webpack_reactRootsDir;
+const REACT_PAGES_DIR = process.env.npm_package_config_webpack_reactPagesDir;
const JEKYLL_SOURCE_DIR = process.env.npm_package_config_jekyll_source;
const JEKYLL_CONFIG_FNAME =
process.env.npm_package_config_jekyll_webpackConfigFilename;
const OUTPUT_DIR = process.env.npm_package_config_webpack_outputDir;
const stylesheetsDirpath = path.resolve(__dirname, TAILWINDCSS_INPUT_DIR);
-const reactRootsDirpath = path.resolve(__dirname, REACT_ROOTS_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(reactRootsDirpath).forEach((file) => {
+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_ROOTS_DIR, file);
+ entryFiles[name] = path.resolve(__dirname, REACT_PAGES_DIR, file);
}
});
@@ -74,4 +74,16 @@ module.exports = {
},
],
},
+ plugins: [
+ new webpack.DefinePlugin({
+ "process.env": {
+ MATOMO_URL: process.env.MATOMO_URL
+ ? "'" + process.env.MATOMO_URL + "'"
+ : undefined,
+ MATOMO_TAG_MANAGER_CONTAINER: process.env.MATOMO_TAG_MANAGER_CONTAINER
+ ? "'" + process.env.MATOMO_TAG_MANAGER_CONTAINER + "'"
+ : undefined
+ }
+ })
+ ]
};