This is an automated email from the ASF dual-hosted git repository.

juzhiyuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-website.git


The following commit(s) were added to refs/heads/master by this push:
     new 4fa9fdf58f9 feat: adapt blog pages, EventPosterCard for mobile (#1238)
4fa9fdf58f9 is described below

commit 4fa9fdf58f902fc2019a6456cb261d220c82796b
Author: Young <[email protected]>
AuthorDate: Tue Jul 26 23:00:30 2022 +0800

    feat: adapt blog pages, EventPosterCard for mobile (#1238)
---
 blog/src/theme/BlogLayout/index.tsx                |   5 +-
 blog/src/theme/BlogListPage/index.tsx              | 127 +------------
 blog/src/theme/BlogListPage/style.module.scss      | 202 --------------------
 .../theme/{BlogListPage => BlogPosts}/index.tsx    | 163 +++++++++-------
 blog/src/theme/BlogPosts/style.module.scss         | 209 +++++++++++++++++++++
 blog/src/theme/BlogTagsPostsPage/index.tsx         | 110 +----------
 blog/src/theme/BlogTagsPostsPage/style.module.scss | 126 -------------
 website/src/components/EventPosterCard.tsx         |  49 ++---
 website/src/css/event-poster-card.module.scss      |   7 +
 9 files changed, 352 insertions(+), 646 deletions(-)

diff --git a/blog/src/theme/BlogLayout/index.tsx 
b/blog/src/theme/BlogLayout/index.tsx
index b9b335a4440..1020d6433d2 100644
--- a/blog/src/theme/BlogLayout/index.tsx
+++ b/blog/src/theme/BlogLayout/index.tsx
@@ -20,7 +20,7 @@ import {
   TwitterIcon,
   TwitterShareButton,
 } from 'react-share';
-
+import useWindowType from '@theme/hooks/useWindowSize';
 import type { Props } from '@theme/BlogLayout';
 import style from './style.module.scss';
 
@@ -50,6 +50,7 @@ const BlogLayout = (props: Props): JSX.Element => {
     sidebar, toc, children, metadata, ...layoutProps
   } = props;
   const hasSidebar = sidebar && sidebar.items.length > 0;
+  const windowType = useWindowType();
 
   return (
     <Layout {...layoutProps}>
@@ -61,7 +62,7 @@ const BlogLayout = (props: Props): JSX.Element => {
             </aside>
           )}
           <div className={clsx({ col: true, 'col--10': toc })}>{children}</div>
-          {toc && (
+          {toc && windowType !== 'mobile' && (
             <div className={clsx('col col--2', style.section)}>
               {metadata && <Share metadata={metadata} />}
               <section className={style.tocSection}>
diff --git a/blog/src/theme/BlogListPage/index.tsx 
b/blog/src/theme/BlogListPage/index.tsx
index 728af4c97b0..531ae9cf479 100644
--- a/blog/src/theme/BlogListPage/index.tsx
+++ b/blog/src/theme/BlogListPage/index.tsx
@@ -12,106 +12,10 @@ import useDocusaurusContext from 
'@docusaurus/useDocusaurusContext';
 import BlogLayout from '@theme/BlogLayout';
 import BlogListPaginator from '@theme/BlogListPaginator';
 import type { Props } from '@theme/BlogListPage';
-import Link from '@docusaurus/Link';
-import type { Props as OldBlogPostItemProps } from '@theme/BlogPostItem';
-// eslint-disable-next-line import/no-extraneous-dependencies
-import { MDXProvider } from '@mdx-js/react';
-import type { ScrollPosition } from 'react-lazy-load-image-component';
-import { trackWindowScroll, LazyLoadImage } from 
'react-lazy-load-image-component';
-import Avvvatars from 'avvvatars-react';
-import clsx from 'clsx';
-import style from './style.module.scss';
+import BlogPosts from '../BlogPosts';
 
-const components = {
-  blockquote: ({ children }) => children,
-  p: ({ children }) => <p>{children.length > 200 ? `${children.slice(0, 
200)}...` : children}</p>,
-  a: ({ children }) => children,
-};
-
-const defaultImg = '/img/default-blog-header.jpg';
-
-type BlogPostItemProps = OldBlogPostItemProps & {
-  scrollPosition: ScrollPosition;
-};
-
-type BlogListPageProps = Props & {
-  scrollPosition: ScrollPosition;
-};
-
-const BlogPostItem: FC<BlogPostItemProps> = (props) => {
-  const {
-    children, frontMatter, assets, metadata, scrollPosition,
-  } = props;
-  const {
-    date, formattedDate, permalink, tags, title, authors,
-  } = metadata;
-
-  const image = assets.image ?? frontMatter.image ?? defaultImg;
-
-  return (
-    <article itemProp="blogPost" itemScope 
itemType="http://schema.org/BlogPosting";>
-      <Link itemProp="url" to={permalink} aria-label={`Read more about 
${title}`}>
-        <LazyLoadImage
-          height={232}
-          width={605}
-          src={image}
-          alt={title}
-          effect="opacity"
-          visibleByDefault={image === defaultImg}
-          scrollPosition={scrollPosition}
-        />
-      </Link>
-      <div className={style.content}>
-        <header>
-          {tags.length > 0 && (
-            <div className={style.tags}>
-              {tags.slice(0, 3).map((tag) => (
-                <a key={tag.permalink} href={tag.permalink}>
-                  {tag.label}
-                </a>
-              ))}
-            </div>
-          )}
-          <Link itemProp="url" to={permalink} aria-label={`Read more about 
${title}`}>
-            <h2>{title}</h2>
-            {children && <MDXProvider 
components={components}>{children}</MDXProvider>}
-          </Link>
-        </header>
-        <footer className={style.footer}>
-          {authors.length > 0 && (
-            <>
-              <div className={style.authors}>
-                {authors.reverse().map((author) => (author.imageURL ? (
-                  <LazyLoadImage
-                    className={style.author}
-                    key={author.name}
-                    src={author.imageURL}
-                    width={32}
-                    height={32}
-                    scrollPosition={scrollPosition}
-                  />
-                ) : (
-                  <div className={style.author} key={author.name}>
-                    <Avvvatars value={author.name as string} />
-                  </div>
-                )))}
-              </div>
-              <div className={style.divider}>•</div>
-            </>
-          )}
-          <time dateTime={date} itemProp="datePublished">
-            {formattedDate}
-          </time>
-        </footer>
-      </div>
-    </article>
-  );
-};
-
-const BlogListPage: FC<BlogListPageProps> = (props) => {
-  const {
-    metadata, items, sidebar, scrollPosition,
-  } = props;
+const BlogListPage: FC<Props> = (props) => {
+  const { metadata, items, sidebar } = props;
   const {
     siteConfig: { title: siteTitle },
   } = useDocusaurusContext();
@@ -123,10 +27,6 @@ const BlogListPage: FC<BlogListPageProps> = (props) => {
     <BlogLayout
       title={title}
       description={blogDescription}
-      wrapperClassName={clsx({
-        [style.normalPage]: true,
-        [style.firstPage]: !metadata.previousPage,
-      })}
       searchMetadatas={{
         // assign unique search tag to exclude this page from search results!
         tag: 'blog_posts_list',
@@ -134,23 +34,14 @@ const BlogListPage: FC<BlogListPageProps> = (props) => {
       sidebar={sidebar}
       toc={false}
     >
-      <main itemScope itemType="http://schema.org/Blog";>
-        {items.map(({ content: BlogPostContent }) => (
-          <BlogPostItem
-            key={BlogPostContent.metadata.permalink}
-            frontMatter={BlogPostContent.frontMatter}
-            assets={BlogPostContent.assets}
-            metadata={BlogPostContent.metadata}
-            truncated={BlogPostContent.metadata.truncated}
-            scrollPosition={scrollPosition}
-          >
-            <BlogPostContent />
-          </BlogPostItem>
-        ))}
-      </main>
+      <BlogPosts
+        itemType="http://schema.org/Blog";
+        items={items}
+        isFirstPage={!metadata.previousPage}
+      />
       <BlogListPaginator metadata={metadata} />
     </BlogLayout>
   );
 };
 
-export default trackWindowScroll(BlogListPage);
+export default BlogListPage;
diff --git a/blog/src/theme/BlogListPage/style.module.scss 
b/blog/src/theme/BlogListPage/style.module.scss
deleted file mode 100644
index 9f6934e117d..00000000000
--- a/blog/src/theme/BlogListPage/style.module.scss
+++ /dev/null
@@ -1,202 +0,0 @@
-/* stylelint-disable no-descending-specificity */
-.normalPage {
-  margin: 5rem 2rem;
-  box-sizing: content-box;
-
-  main {
-    width: fit-content;
-    display: grid;
-    grid-template-columns: repeat(3, 430px);
-    margin: 0 auto;
-    align-items: start;
-    font-family: apple-system, system-ui, sans-serif;
-
-    article {
-      margin: 0 1.25rem 2.5rem;
-      border-radius: 1rem;
-      overflow: hidden;
-      border: 2px solid transparent;
-      transition: all 0.3s ease-in-out;
-      // filter: drop-shadow(0 1px 1px rgb(0 0 0 / 10%));
-
-      & > a {
-        width: 100%;
-        height: 100%;
-        overflow: hidden;
-
-        img {
-          object-fit: cover;
-          width: 100%;
-          max-width: unset;
-          // filter: drop-shadow(0 1px 0 rgb(0 0 0 / 4%));
-          transform-origin: center center;
-          transition: all 0.3s ease-in-out;
-        }
-      }
-
-      & .content {
-        padding: 0 1rem 1rem;
-
-        header {
-          & .tags {
-            display: flex;
-            justify-content: flex-start;
-            overflow: hidden;
-            text-overflow: ellipsis;
-            margin: 0.8rem 0;
-
-            & > a {
-              color: var(--ifm-link-color);
-              margin-right: 0.5rem;
-              text-transform: uppercase;
-              font-size: 0.66rem;
-
-              &:hover {
-                opacity: 0.6;
-              }
-            }
-          }
-
-          h2 {
-            font-size: 1.375rem;
-            line-height: 1.2em;
-            color: #222;
-            margin-top: 0.8rem;
-            margin-bottom: 0.5em;
-            transition: all 0.3s ease-in-out;
-
-            &:hover {
-              opacity: 0.6;
-            }
-          }
-
-          p {
-            color: #1d1d1f;
-            max-height: #{1.7 * 3}em;
-            overflow-y: hidden;
-            text-overflow: ellipsis;
-            font-weight: 300;
-            margin-bottom: 2rem;
-          }
-        }
-
-        & .footer {
-          display: flex;
-          align-items: center;
-        }
-
-        & .authors {
-          display: flex;
-          flex-direction: row-reverse;
-
-          & .author {
-            width: 32px;
-            height: 32px;
-            border-radius: 50%;
-            margin-left: -1rem;
-
-            &:last-child {
-              margin-left: 0;
-            }
-          }
-        }
-
-        & .divider {
-          margin: 0 0.5rem;
-        }
-      }
-
-      &:hover {
-        border-color: var(--ifm-color-primary);
-        transform: translateY(-20px);
-
-        & > a {
-          img {
-            transform: scale3d(1.05, 1.05, 1);
-          }
-        }
-
-        h2 {
-          opacity: 0.6;
-        }
-
-        & .tags:hover + a > h2 {
-          opacity: 1;
-        }
-      }
-    }
-  }
-}
-
-.firstPage {
-  main {
-    grid-template-columns: repeat(2, 645px);
-
-    article {
-      & > a {
-        img {
-          width: 100%;
-        }
-      }
-
-      .content {
-        padding: 0 1.875rem 1.875rem;
-      }
-
-      &:first-of-type {
-        grid-column: 1 / 3;
-        display: flex;
-        filter: none;
-        margin-top: 0;
-        margin-bottom: 5rem;
-
-        & > a {
-          border-radius: 1rem;
-          width: 601px;
-          height: auto;
-          flex-shrink: 0;
-
-          img {
-            height: 100%;
-            width: 100%;
-          }
-        }
-
-        .content {
-          padding: 1rem 2rem;
-
-          header {
-            &::before {
-              content: "LATEST POST";
-              font-size: 0.7rem;
-              font-weight: 800;
-            }
-
-            & .tags > a {
-              font-size: 0.8rem;
-            }
-
-            h2 {
-              font-size: 2.55rem;
-            }
-
-            p {
-              font-size: 1.2rem;
-            }
-          }
-        }
-
-        &:hover {
-          border-color: transparent;
-          transform: none;
-
-          & > a {
-            img {
-              transform: scale3d(1.2, 1.2, 1) rotate3d(0, 0, 1, -2deg);
-            }
-          }
-        }
-      }
-    }
-  }
-}
diff --git a/blog/src/theme/BlogListPage/index.tsx 
b/blog/src/theme/BlogPosts/index.tsx
similarity index 52%
copy from blog/src/theme/BlogListPage/index.tsx
copy to blog/src/theme/BlogPosts/index.tsx
index 728af4c97b0..ae9451d1fbd 100644
--- a/blog/src/theme/BlogListPage/index.tsx
+++ b/blog/src/theme/BlogPosts/index.tsx
@@ -1,17 +1,4 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-import type { FC } from 'react';
-import React from 'react';
-
-import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
-import BlogLayout from '@theme/BlogLayout';
-import BlogListPaginator from '@theme/BlogListPaginator';
-import type { Props } from '@theme/BlogListPage';
+/* eslint-disable react/require-default-props, 
@typescript-eslint/no-explicit-any */
 import Link from '@docusaurus/Link';
 import type { Props as OldBlogPostItemProps } from '@theme/BlogPostItem';
 // eslint-disable-next-line import/no-extraneous-dependencies
@@ -20,6 +7,9 @@ import type { ScrollPosition } from 
'react-lazy-load-image-component';
 import { trackWindowScroll, LazyLoadImage } from 
'react-lazy-load-image-component';
 import Avvvatars from 'avvvatars-react';
 import clsx from 'clsx';
+import type { FC, HTMLAttributes, DetailedHTMLProps } from 'react';
+import React from 'react';
+import 'react-lazy-load-image-component/src/effects/blur.css';
 import style from './style.module.scss';
 
 const components = {
@@ -30,18 +20,37 @@ const components = {
 
 const defaultImg = '/img/default-blog-header.jpg';
 
-type BlogPostItemProps = OldBlogPostItemProps & {
+interface LazyProps {
   scrollPosition: ScrollPosition;
-};
+  delayMethod?: string;
+  delayTime?: number;
+  useIntersectionObserver?: boolean;
+}
 
-type BlogListPageProps = Props & {
-  scrollPosition: ScrollPosition;
-};
+type BlogPostItemProps = OldBlogPostItemProps & LazyProps;
+
+type BlogPostsProps = DetailedHTMLProps<HTMLAttributes<HTMLElement>, 
HTMLElement> & {
+  items: any;
+  isFirstPage?: boolean;
+} & LazyProps;
 
 const BlogPostItem: FC<BlogPostItemProps> = (props) => {
   const {
-    children, frontMatter, assets, metadata, scrollPosition,
+    children,
+    frontMatter,
+    assets,
+    metadata,
+    scrollPosition,
+    delayMethod,
+    delayTime,
+    useIntersectionObserver,
   } = props;
+  const delayProps = {
+    scrollPosition,
+    delayMethod,
+    delayTime,
+    useIntersectionObserver,
+  };
   const {
     date, formattedDate, permalink, tags, title, authors,
   } = metadata;
@@ -56,9 +65,24 @@ const BlogPostItem: FC<BlogPostItemProps> = (props) => {
           width={605}
           src={image}
           alt={title}
-          effect="opacity"
+          effect="blur"
+          placeholder={(
+            <div>
+              <noscript>
+                <img src={image} alt={title} />
+              </noscript>
+              <div
+                style={{
+                  width: 605,
+                  height: 232,
+                  borderRadius: '1rem',
+                  backgroundColor: '#d2d2d7',
+                }}
+              />
+            </div>
+          )}
           visibleByDefault={image === defaultImg}
-          scrollPosition={scrollPosition}
+          {...delayProps}
         />
       </Link>
       <div className={style.content}>
@@ -88,7 +112,23 @@ const BlogPostItem: FC<BlogPostItemProps> = (props) => {
                     src={author.imageURL}
                     width={32}
                     height={32}
-                    scrollPosition={scrollPosition}
+                    effect="blur"
+                    placeholder={(
+                      <div>
+                        <noscript>
+                          <img src={author.name} alt={author.imageURL} />
+                        </noscript>
+                        <div
+                          style={{
+                            width: 32,
+                            height: 32,
+                            borderRadius: '50%',
+                            backgroundColor: '#d2d2d7',
+                          }}
+                        />
+                      </div>
+                      )}
+                    {...delayProps}
                   />
                 ) : (
                   <div className={style.author} key={author.name}>
@@ -108,49 +148,36 @@ const BlogPostItem: FC<BlogPostItemProps> = (props) => {
   );
 };
 
-const BlogListPage: FC<BlogListPageProps> = (props) => {
-  const {
-    metadata, items, sidebar, scrollPosition,
-  } = props;
-  const {
-    siteConfig: { title: siteTitle },
-  } = useDocusaurusContext();
-  const { blogDescription, blogTitle, permalink } = metadata;
-  const isBlogOnlyMode = permalink === '/';
-  const title = isBlogOnlyMode ? siteTitle : blogTitle;
-
-  return (
-    <BlogLayout
-      title={title}
-      description={blogDescription}
-      wrapperClassName={clsx({
-        [style.normalPage]: true,
-        [style.firstPage]: !metadata.previousPage,
-      })}
-      searchMetadatas={{
-        // assign unique search tag to exclude this page from search results!
-        tag: 'blog_posts_list',
-      }}
-      sidebar={sidebar}
-      toc={false}
-    >
-      <main itemScope itemType="http://schema.org/Blog";>
-        {items.map(({ content: BlogPostContent }) => (
-          <BlogPostItem
-            key={BlogPostContent.metadata.permalink}
-            frontMatter={BlogPostContent.frontMatter}
-            assets={BlogPostContent.assets}
-            metadata={BlogPostContent.metadata}
-            truncated={BlogPostContent.metadata.truncated}
-            scrollPosition={scrollPosition}
-          >
-            <BlogPostContent />
-          </BlogPostItem>
-        ))}
-      </main>
-      <BlogListPaginator metadata={metadata} />
-    </BlogLayout>
-  );
-};
+const BlogPosts: FC<BlogPostsProps> = ({
+  items,
+  isFirstPage = false,
+  scrollPosition,
+  delayMethod,
+  delayTime,
+  useIntersectionObserver,
+  ...props
+}) => (
+  <main
+    className={clsx({
+      [style.normalPage]: true,
+      [style.firstPage]: isFirstPage,
+    })}
+    itemScope
+    {...props}
+  >
+    {items.map(({ content: BlogPostContent }) => (
+      <BlogPostItem
+        key={BlogPostContent.metadata.permalink}
+        frontMatter={BlogPostContent.frontMatter}
+        assets={BlogPostContent.assets}
+        metadata={BlogPostContent.metadata}
+        truncated={BlogPostContent.metadata.truncated}
+        {...{ delayMethod, delayTime, useIntersectionObserver }}
+      >
+        <BlogPostContent />
+      </BlogPostItem>
+    ))}
+  </main>
+);
 
-export default trackWindowScroll(BlogListPage);
+export default trackWindowScroll(BlogPosts);
diff --git a/blog/src/theme/BlogPosts/style.module.scss 
b/blog/src/theme/BlogPosts/style.module.scss
new file mode 100644
index 00000000000..5eee636f8fd
--- /dev/null
+++ b/blog/src/theme/BlogPosts/style.module.scss
@@ -0,0 +1,209 @@
+/* stylelint-disable no-descending-specificity */
+@import "../../css/util";
+
+main.normalPage {
+  width: fit-content;
+  display: grid;
+  grid-template-columns: repeat(3, 430px);
+  margin: 5rem auto 0;
+  align-items: start;
+  font-family: apple-system, system-ui, sans-serif;
+
+  article {
+    margin: 0 1.25rem 2.5rem;
+    border-radius: 1rem;
+    overflow: hidden;
+    border: 2px solid transparent;
+    transition: all 0.3s ease-in-out;
+    // filter: drop-shadow(0 1px 1px rgb(0 0 0 / 10%));
+
+    & > a {
+      width: 100%;
+      height: 100%;
+      overflow: hidden;
+
+      img {
+        object-fit: cover;
+        width: 100%;
+        max-width: unset;
+        // filter: drop-shadow(0 1px 0 rgb(0 0 0 / 4%));
+        transform-origin: center center;
+        transition: all 0.3s ease-in-out;
+      }
+    }
+
+    & .content {
+      padding: 0 1rem 1rem;
+
+      header {
+        & .tags {
+          display: flex;
+          justify-content: flex-start;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          margin: 0.8rem 0;
+
+          & > a {
+            color: var(--ifm-link-color);
+            margin-right: 0.5rem;
+            text-transform: uppercase;
+            font-size: 0.66rem;
+
+            &:hover {
+              opacity: 0.6;
+            }
+          }
+        }
+
+        h2 {
+          font-size: 1.375rem;
+          line-height: 1.2em;
+          color: #222;
+          margin-top: 0.8rem;
+          margin-bottom: 0.5em;
+          transition: all 0.3s ease-in-out;
+
+          &:hover {
+            opacity: 0.6;
+          }
+        }
+
+        p {
+          color: #1d1d1f;
+          max-height: #{1.7 * 3}em;
+          overflow-y: hidden;
+          text-overflow: ellipsis;
+          font-weight: 300;
+          margin-bottom: 2rem;
+        }
+      }
+
+      & .footer {
+        display: flex;
+        align-items: center;
+      }
+
+      & .authors {
+        display: flex;
+        flex-direction: row-reverse;
+
+        & .author,
+        & > span {
+          width: 32px;
+          height: 32px;
+          border-radius: 50%;
+          margin-left: -1rem;
+
+          &:last-child {
+            margin-left: 0;
+          }
+        }
+      }
+
+      & .divider {
+        margin: 0 0.5rem;
+      }
+    }
+
+    &:hover {
+      border-color: var(--ifm-color-primary);
+      transform: translateY(-20px);
+
+      & > a {
+        img {
+          transform: scale3d(1.05, 1.05, 1);
+        }
+      }
+
+      h2 {
+        opacity: 0.6;
+      }
+
+      & .tags:hover + a > h2 {
+        opacity: 1;
+      }
+    }
+  }
+}
+
+@include respond-above(sm) {
+  main.firstPage {
+    grid-template-columns: repeat(2, 645px);
+
+    article {
+      & > a {
+        img {
+          width: 100%;
+        }
+      }
+
+      .content {
+        padding: 0 1.875rem 1.875rem;
+      }
+
+      &:first-of-type {
+        grid-column: 1 / 3;
+        display: flex;
+        filter: none;
+        margin-top: 0;
+        margin-bottom: 5rem;
+
+        & > a {
+          border-radius: 1rem;
+          width: 601px;
+          height: auto;
+          flex-shrink: 0;
+
+          img {
+            height: 100%;
+            width: 100%;
+          }
+        }
+
+        .content {
+          padding: 1rem 2rem;
+
+          header {
+            &::before {
+              content: "LATEST POST";
+              font-size: 0.7rem;
+              font-weight: 800;
+            }
+
+            & .tags > a {
+              font-size: 0.8rem;
+            }
+
+            h2 {
+              font-size: 2.55rem;
+            }
+
+            p {
+              font-size: 1.2rem;
+            }
+          }
+        }
+
+        &:hover {
+          border-color: transparent;
+          transform: none;
+
+          & > a {
+            img {
+              transform: scale3d(1.2, 1.2, 1) rotate3d(0, 0, 1, -2deg);
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+@include respond-below(sm) {
+  main.normalPage {
+    display: flex;
+    flex-direction: column;
+    width: 100%;
+    margin: 0;
+  }
+}
diff --git a/blog/src/theme/BlogTagsPostsPage/index.tsx 
b/blog/src/theme/BlogTagsPostsPage/index.tsx
index 570ccf56bd5..55eb2559612 100644
--- a/blog/src/theme/BlogTagsPostsPage/index.tsx
+++ b/blog/src/theme/BlogTagsPostsPage/index.tsx
@@ -6,28 +6,16 @@
  * LICENSE file in the root directory of this source tree.
  */
 
-import type { FC } from 'react';
 import React from 'react';
 
 import BlogLayout from '@theme/BlogLayout';
 import BlogListPaginator from '@theme/BlogListPaginator';
 import type { Props } from '@theme/BlogTagsPostsPage';
 import Link from '@docusaurus/Link';
-import type { Props as BlogPostItemProps } from '@theme/BlogPostItem';
-// eslint-disable-next-line import/no-extraneous-dependencies
-import { MDXProvider } from '@mdx-js/react';
-import { LazyLoadImage } from 'react-lazy-load-image-component';
-import Avvvatars from 'avvvatars-react';
-import clsx from 'clsx';
 import Translate, { translate } from '@docusaurus/Translate';
 import { usePluralForm } from '@docusaurus/theme-common';
 import style from './style.module.scss';
-
-const components = {
-  blockquote: ({ children }) => children,
-  p: ({ children }) => <p>{children.length > 200 ? `${children.slice(0, 
200)}...` : children}</p>,
-  a: ({ children }) => children,
-};
+import BlogPosts from '../BlogPosts';
 
 function useBlogPostsPlural() {
   const { selectMessage } = usePluralForm();
@@ -45,83 +33,6 @@ function useBlogPostsPlural() {
   );
 }
 
-const BlogPostItem: FC<BlogPostItemProps> = (props) => {
-  const {
-    children,
-    frontMatter,
-    assets,
-    metadata,
-  } = props;
-  const {
-    date,
-    formattedDate,
-    permalink,
-    tags,
-    title,
-    authors,
-  } = metadata;
-
-  const image = assets.image ?? frontMatter.image ?? 
'/img/default-blog-header.jpg';
-
-  return (
-    <article
-      itemProp="blogPost"
-      itemScope
-      itemType="http://schema.org/BlogPosting";
-    >
-      <Link itemProp="url" to={permalink} aria-label={`Read more about 
${title}`}>
-        <LazyLoadImage src={image} alt={title} height={203} width={384} />
-      </Link>
-      <div className={style.content}>
-        <header>
-          {tags.length > 0 && (
-            <div className={style.tags}>
-              {tags.slice(0, 3).map((tag) => (
-                <a key={tag.permalink} href={tag.permalink}>
-                  {tag.label}
-                </a>
-              ))}
-            </div>
-          )}
-          <Link itemProp="url" to={permalink} aria-label={`Read more about 
${title}`}>
-            <h2>{title}</h2>
-            {children && <MDXProvider 
components={components}>{children}</MDXProvider>}
-          </Link>
-        </header>
-        <footer className={style.footer}>
-          {authors.length > 0
-            && (
-              <>
-                <div className={style.authors}>
-                  {authors.reverse().map((author) => (
-                    author.imageURL
-                      ? (
-                        <LazyLoadImage
-                          className={style.author}
-                          key={author.name}
-                          src={author.imageURL}
-                        />
-                      )
-                      : (
-                        <div className={style.author}>
-                          <Avvvatars
-                            key={author.name}
-                            value={author.name as string}
-                          />
-                        </div>
-                      )
-                  ))}
-                </div>
-                <div className={style.divider}>•</div>
-              </>
-            )}
-          <time dateTime={date} itemProp="datePublished">{formattedDate}</time>
-        </footer>
-      </div>
-    </article>
-  );
-};
-
 const BlogTagsPostsPage = (props: Props): JSX.Element => {
   const { metadata, items, sidebar } = props;
   const { allTagsPath, name: tagName, count } = metadata;
@@ -138,9 +49,6 @@ const BlogTagsPostsPage = (props: Props): JSX.Element => {
   return (
     <BlogLayout
       title={title}
-      wrapperClassName={clsx({
-        [style.normalPage]: true, [style.firstPage]: !metadata.previousPage,
-      })}
       searchMetadatas={{
         // assign unique search tag to exclude this page from search results!
         tag: 'blog_tags_posts',
@@ -159,21 +67,7 @@ const BlogTagsPostsPage = (props: Props): JSX.Element => {
           </Translate>
         </Link>
       </header>
-      <main
-        itemScope
-      >
-        {items.map(({ content: BlogPostContent }) => (
-          <BlogPostItem
-            key={BlogPostContent.metadata.permalink}
-            frontMatter={BlogPostContent.frontMatter}
-            assets={BlogPostContent.assets}
-            metadata={BlogPostContent.metadata}
-            truncated={BlogPostContent.metadata.truncated}
-          >
-            <BlogPostContent />
-          </BlogPostItem>
-        ))}
-      </main>
+      <BlogPosts items={items} />
       <BlogListPaginator metadata={metadata} />
     </BlogLayout>
   );
diff --git a/blog/src/theme/BlogTagsPostsPage/style.module.scss 
b/blog/src/theme/BlogTagsPostsPage/style.module.scss
index 07114a969b6..be7544dbd05 100644
--- a/blog/src/theme/BlogTagsPostsPage/style.module.scss
+++ b/blog/src/theme/BlogTagsPostsPage/style.module.scss
@@ -1,130 +1,4 @@
-/* stylelint-disable no-descending-specificity */
 .header {
   text-align: center;
   margin-bottom: 4rem;
 }
-
-.normalPage {
-  margin: 5rem 2rem;
-  box-sizing: content-box;
-
-  main {
-    width: fit-content;
-    display: grid;
-    grid-template-columns: repeat(3, 430px);
-    margin: 0 auto;
-    align-items: start;
-    font-family: apple-system, system-ui, sans-serif;
-
-    article {
-      margin: 0 1.25rem 2.5rem;
-      border-radius: 1rem;
-      overflow: hidden;
-      background-color: #fffffd;
-      filter: drop-shadow(0 1px 1px rgb(0 0 0 / 10%));
-
-      & > a {
-        width: 100%;
-        height: 100%;
-        overflow: hidden;
-
-        img {
-          object-fit: cover;
-          width: 100%;
-          max-width: unset;
-          filter: drop-shadow(0 1px 0 rgb(0 0 0 / 4%));
-          transform-origin: center center;
-          transition: all 0.3s ease-in-out;
-        }
-      }
-
-      & .content {
-        padding: 0 1rem 1rem;
-
-        header {
-          & .tags {
-            display: flex;
-            justify-content: flex-start;
-            overflow: hidden;
-            text-overflow: ellipsis;
-            margin: 0.8rem 0;
-
-            & > a {
-              color: var(--ifm-link-color);
-              margin-right: 0.5rem;
-              text-transform: uppercase;
-              font-size: 0.66rem;
-
-              &:hover {
-                opacity: 0.6;
-              }
-            }
-          }
-
-          h2 {
-            font-size: 1.375rem;
-            line-height: 1.2em;
-            color: #222;
-            margin-top: 0.8rem;
-            margin-bottom: 0.5em;
-            transition: all 0.3s ease-in-out;
-
-            &:hover {
-              opacity: 0.6;
-            }
-          }
-
-          p {
-            color: #999;
-            max-height: #{1.7 * 3}em;
-            overflow-y: hidden;
-            text-overflow: ellipsis;
-            font-weight: 300;
-            margin-bottom: 2rem;
-          }
-        }
-
-        & .footer {
-          display: flex;
-          align-items: center;
-        }
-
-        & .authors {
-          display: flex;
-          flex-direction: row-reverse;
-
-          & .author {
-            width: 32px;
-            height: 32px;
-            border-radius: 50%;
-            margin-left: -1rem;
-
-            &:last-child {
-              margin-left: 0;
-            }
-          }
-        }
-
-        & .divider {
-          margin: 0 0.5rem;
-        }
-      }
-
-      &:hover {
-        & > a {
-          img {
-            transform: scale3d(1.05, 1.05, 1);
-          }
-        }
-
-        h2 {
-          opacity: 0.6;
-        }
-
-        & .tags:hover + a > h2 {
-          opacity: 1;
-        }
-      }
-    }
-  }
-}
diff --git a/website/src/components/EventPosterCard.tsx 
b/website/src/components/EventPosterCard.tsx
index 331d859a958..eb68cbb61b9 100644
--- a/website/src/components/EventPosterCard.tsx
+++ b/website/src/components/EventPosterCard.tsx
@@ -1,11 +1,10 @@
 import type { FC } from 'react';
-import React, {
-  useCallback, useMemo, useEffect,
-} from 'react';
+import React, { useCallback, useMemo, useEffect } from 'react';
 import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
 import { LazyLoadImage } from 'react-lazy-load-image-component';
 import { useSpring, animated } from 'react-spring';
 import useSessionStorage from 'react-use/lib/useSessionStorage';
+// eslint-disable-next-line import/no-unresolved, import/extensions
 import config from '../../../config/event-poster-card.json';
 import style from '../css/event-poster-card.module.scss';
 
@@ -19,10 +18,15 @@ interface EventPosterCardInfo {
 
 const SHOW_STORE_KEY = 'SHOW_EVENT_ENTRY';
 
-const EventPosterCard:FC<Omit<EventPosterCardInfo, 'show' | 'expire'>> = 
(props) => {
+const EventPosterCard: FC<Omit<EventPosterCardInfo, 'show' | 'expire'>> = 
(props) => {
   const { image, links, width } = props;
-  const { i18n: { currentLocale } } = useDocusaurusContext();
-  const link = useMemo(() => (typeof links === 'string' ? links : 
links[currentLocale]), [currentLocale]);
+  const {
+    i18n: { currentLocale },
+  } = useDocusaurusContext();
+  const link = useMemo(
+    () => (typeof links === 'string' ? links : links[currentLocale]),
+    [currentLocale]
+  );
   const [, setStoreShow] = useSessionStorage(SHOW_STORE_KEY, 'true');
 
   const [styles, api] = useSpring(() => ({
@@ -43,29 +47,30 @@ const EventPosterCard:FC<Omit<EventPosterCardInfo, 'show' | 
'expire'>> = (props)
   }, []);
 
   const onClose = useCallback(
-    async () => Promise.all(api.start({
-      to: {
-        x: 500,
-        opacity: 0,
-      },
-    }))
-      .then(() => setStoreShow('false')),
-    [api],
+    async () =>
+      Promise.all(
+        api.start({
+          to: {
+            x: 500,
+            opacity: 0,
+          },
+        })
+      ).then(() => setStoreShow('false')),
+    [api]
   );
 
   return (
     <animated.div className={style.picWrapper} style={styles}>
       <button className={style.closeBtn} onClick={onClose} type="button">
-        <svg
-          role="img"
-          xmlns="http://www.w3.org/2000/svg";
-          viewBox="0 0 352 512"
-        >
-          <path fill="currentColor" d="M242.72 256l100.07-100.07c12.28-12.28 
12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 
75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 
32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 
22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 
12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z" />
+        <svg role="img" xmlns="http://www.w3.org/2000/svg"; viewBox="0 0 352 
512">
+          <path
+            fill="currentColor"
+            d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 
0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 
89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 
44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 
12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 
0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
+          />
         </svg>
       </button>
       <a href={link} onClick={onClose} target="_blank" rel="noreferrer">
-        <LazyLoadImage src={image} alt={link} width={width} />
+        <LazyLoadImage src={image} alt={link} width={width} style={{ maxWidth: 
'100vw' }} />
       </a>
     </animated.div>
   );
@@ -76,7 +81,7 @@ const EventPosterCardWrapper: FC = () => {
   const { show, expire, ...rest } = config;
   const expireTimestamp = new Date(expire).getTime();
 
-  if (show && !storeShow && (expireTimestamp > Date.now())) {
+  if (show && !storeShow && expireTimestamp > Date.now()) {
     return <EventPosterCard {...rest} />;
   }
 
diff --git a/website/src/css/event-poster-card.module.scss 
b/website/src/css/event-poster-card.module.scss
index 492e85daf20..07bbcff1c87 100644
--- a/website/src/css/event-poster-card.module.scss
+++ b/website/src/css/event-poster-card.module.scss
@@ -1,3 +1,5 @@
+@import "./util";
+
 .picWrapper {
   position: fixed;
   display: flex;
@@ -9,6 +11,11 @@
   border: 0;
   box-shadow: 0 0 20px -12px #626365;
 
+  @include respond-below(sm) {
+    right: 0;
+    bottom: 0;
+  }
+
   & > a {
     display: flex;
   }

Reply via email to