aboutsummaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2024-03-23 18:02:45 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2024-03-23 18:07:21 +0100
commitfbd41d395916176dde11bb0e417f1210f34eb4ab (patch)
tree7384a50b1a90ba5909d8f93f589df661640681e6 /src/components
parentSimplify compression (diff)
downloadblog-fbd41d395916176dde11bb0e417f1210f34eb4ab.tar.gz
blog-fbd41d395916176dde11bb0e417f1210f34eb4ab.tar.zst
blog-fbd41d395916176dde11bb0e417f1210f34eb4ab.zip
Add blog
Site structure follows SEO tips from https://johnnyreilly.com/how-we-fixed-my-seo * The blog pages have as simple of an URL as possible. To this end, the home page of the site is actually the first index page of the blog. * Customize the blog index page BlogListPage component to show the landing page as the first index page. * Rename /archive to /blog to avoid a dated feel. * Remove the date from post URLs using the slug property.
Diffstat (limited to 'src/components')
-rw-r--r--src/components/ActiveSectionProvider.tsx2
-rw-r--r--src/components/Landing.tsx31
-rw-r--r--src/components/landing/sections/Blog.module.css28
-rw-r--r--src/components/landing/sections/Blog.tsx95
-rw-r--r--src/components/landing/sections/Hero.module.css10
5 files changed, 163 insertions, 3 deletions
diff --git a/src/components/ActiveSectionProvider.tsx b/src/components/ActiveSectionProvider.tsx
index 022dbad..0d491ac 100644
--- a/src/components/ActiveSectionProvider.tsx
+++ b/src/components/ActiveSectionProvider.tsx
@@ -46,7 +46,7 @@ export default function ActiveSectionProvider({
46 if (hash === lastHashRef.current) { 46 if (hash === lastHashRef.current) {
47 return; 47 return;
48 } 48 }
49 // Passing `undefined` to `hash` will give contraol pack to react-router. 49 // Passing `undefined` to `hash` will give control back to react-router.
50 const newURL = `${location.pathname}${location.search}${ 50 const newURL = `${location.pathname}${location.search}${
51 hash ?? location.hash 51 hash ?? location.hash
52 }`; 52 }`;
diff --git a/src/components/Landing.tsx b/src/components/Landing.tsx
new file mode 100644
index 0000000..5eac99b
--- /dev/null
+++ b/src/components/Landing.tsx
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2023 Kristóf Marussy
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7import type { Props } from '@theme/BlogListPage';
8import Layout from '@theme/Layout';
9
10import Blog from './landing/sections/Blog';
11import Contact from './landing/sections/Contact';
12import Hero from './landing/sections/Hero';
13import Publications from './landing/sections/Publications';
14import Research from './landing/sections/Research';
15import Resume from './landing/sections/Resume';
16import TrackActiveSection from './TrackActiveSection';
17
18export default function Home(props: Props) {
19 return (
20 <Layout>
21 <TrackActiveSection>
22 <Hero />
23 <Research />
24 <Blog {...props} />
25 <Publications />
26 <Resume />
27 <Contact />
28 </TrackActiveSection>
29 </Layout>
30 );
31}
diff --git a/src/components/landing/sections/Blog.module.css b/src/components/landing/sections/Blog.module.css
new file mode 100644
index 0000000..6a38a97
--- /dev/null
+++ b/src/components/landing/sections/Blog.module.css
@@ -0,0 +1,28 @@
1/*
2 * SPDX-FileCopyrightText: 2024 Kristóf Marussy
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7.row {
8 margin-bottom: var(--ifm-paragraph-margin-bottom);
9}
10
11.recent-posts {
12 margin-bottom: 0;
13 font-size: var(--ifm-h3-font-size);
14 font-weight: var(--ifm-font-weight-bold);
15 --casl: 0.5;
16 letter-spacing: var(--marussy-heading-tracking);
17}
18
19.date {
20 font-size: 1rem;
21 font-weight: var(--ifm-font-weight-normal);
22 --casl: 0;
23 letter-spacing: 0;
24}
25
26.prev::after {
27 content: ' »';
28}
diff --git a/src/components/landing/sections/Blog.tsx b/src/components/landing/sections/Blog.tsx
new file mode 100644
index 0000000..3ac87db
--- /dev/null
+++ b/src/components/landing/sections/Blog.tsx
@@ -0,0 +1,95 @@
1/*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 * Copyright (c) 2024 Kristóf Marussy <kristof@marussy.com>
4 *
5 * SPDX-License-Identifier: MIT
6 */
7
8import Link from '@docusaurus/Link';
9import type { Props } from '@theme/BlogListPage';
10import type { Content } from '@theme/BlogPostPage';
11import Translate from '@docusaurus/Translate';
12import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
13import clsx from 'clsx';
14
15import Section from '@site/src/components/landing/Section';
16import Subtitle from '@site/src/components/landing/Subtitle';
17
18import styles from './Blog.module.css';
19import React from 'react';
20
21const columnLength = 5;
22
23function Column({
24 items,
25}: {
26 items: { readonly content: Content }[];
27}): React.ReactNode {
28 // Date time format based on
29 // https://github.com/facebook/docusaurus/blob/6f17d5493877ba38d8b4e0b0d468f44401375c30/packages/docusaurus-theme-common/src/utils/IntlUtils.ts
30 const {
31 i18n: { currentLocale, localeConfigs },
32 } = useDocusaurusContext();
33 const calendar = localeConfigs[currentLocale]!.calendar;
34 const dateTimeFormat = new Intl.DateTimeFormat(currentLocale, {
35 calendar,
36 day: 'numeric',
37 month: 'long',
38 year: 'numeric',
39 timeZone: 'UTC',
40 });
41
42 if (items.length === 0) {
43 return null;
44 }
45
46 return (
47 <div className="col col-6">
48 <ul className={styles['recent-posts']}>
49 {items.map(({ content }) => (
50 <li key={content.metadata.date}>
51 <Link to={content.metadata.permalink}>
52 {content.metadata.title}
53 </Link>{' '}
54 <span className={styles.date}>
55 on&nbsp;{dateTimeFormat.format(new Date(content.metadata.date))}
56 </span>
57 </li>
58 ))}
59 </ul>
60 </div>
61 );
62}
63
64export default function Blog(props: Props) {
65 const {
66 items,
67 metadata: { nextPage },
68 } = props;
69 const columnLength = Math.max(1, Math.ceil(items.length / 2));
70 return (
71 <Section id="blog" title="Blog">
72 <div className="container">
73 <section>
74 <Subtitle icon="🗓️">Recent posts</Subtitle>
75 </section>
76 <div className={clsx('row', styles.row)}>
77 <Column items={items.slice(0, columnLength)} />
78 <Column items={items.slice(columnLength)} />
79 </div>
80 {nextPage && (
81 <p>
82 <Link to={nextPage} className={styles.prev}>
83 <Translate
84 id="theme.blog.paginator.olderEntries"
85 description="The label used to navigate to the older blog posts page (next page)"
86 >
87 Older Entries
88 </Translate>
89 </Link>
90 </p>
91 )}
92 </div>
93 </Section>
94 );
95}
diff --git a/src/components/landing/sections/Hero.module.css b/src/components/landing/sections/Hero.module.css
index 67e7d54..0d0e16e 100644
--- a/src/components/landing/sections/Hero.module.css
+++ b/src/components/landing/sections/Hero.module.css
@@ -11,7 +11,7 @@
11 --ifm-link-hover-color: var(--ifm-link-color); 11 --ifm-link-hover-color: var(--ifm-link-color);
12} 12}
13 13
14@media (max-width: 996px) { 14@media (max-width: 576px) {
15 .hero { 15 .hero {
16 padding-top: 2rem; 16 padding-top: 2rem;
17 padding-bottom: 0; 17 padding-bottom: 0;
@@ -65,11 +65,17 @@
65 font-family: var(--ifm-heading-font-family); 65 font-family: var(--ifm-heading-font-family);
66 font-weight: var(--ifm-heading-font-weight); 66 font-weight: var(--ifm-heading-font-weight);
67 --casl: 1; 67 --casl: 1;
68 font-size: 2.5rem; 68 font-size: 3rem;
69 letter-spacing: var(--marussy-heading-tracking); 69 letter-spacing: var(--marussy-heading-tracking);
70 white-space: pre; 70 white-space: pre;
71} 71}
72 72
73@media (max-width: 576px) {
74 .introduction__name {
75 font-size: 2.5rem;
76 }
77}
78
73.cta { 79.cta {
74 display: flex; 80 display: flex;
75 flex-direction: row; 81 flex-direction: row;