This is an automated email from the ASF dual-hosted git repository.
yumeng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake-website.git
The following commit(s) were added to refs/heads/main by this push:
new 204e4ab66c feat: add BlogOverview Page (#406)
204e4ab66c is described below
commit 204e4ab66c06c0d5202e3428d0d35787f92f1a47
Author: Yifu Hu <[email protected]>
AuthorDate: Wed Jan 18 17:35:49 2023 +0800
feat: add BlogOverview Page (#406)
---
docusaurus.config.js | 2 +-
info/Blog/AllPosts.json | 34 +++++++
info/Blog/EditorPickBlog.json | 28 ++++++
package.json | 1 +
src/components/Blog/AllPosts.tsx | 102 +++++++++++++++++++++
src/components/Blog/BlogHeader.tsx | 19 ++++
src/components/Blog/BlogpageBG.tsx | 71 ++++++++++++++
src/components/Blog/EditorPick.tsx | 77 ++++++++++++++++
src/components/Blog/types.ts | 10 ++
src/components/Blog/utils.tsx | 21 +++++
src/pages/blogOverview/index.js | 31 +++++++
static/img/Blog/How DevLake is up and running.png | Bin 0 -> 82993 bytes
static/img/Blog/apache-welcomes-devLake.png | Bin 0 -> 38972 bytes
...atibility-of-apache-devLake-with-postgreSQL.png | Bin 0 -> 154866 bytes
tailwind.config.js | 4 +
15 files changed, 399 insertions(+), 1 deletion(-)
diff --git a/docusaurus.config.js b/docusaurus.config.js
index 7a8f65027c..caa995e0b1 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -162,7 +162,7 @@ const versions = require('./versions.json');
position: 'right'
},
{
- to: '/blog',
+ to: '/blogOverview',
label: 'Blog',
position: 'right'
},
diff --git a/info/Blog/AllPosts.json b/info/Blog/AllPosts.json
new file mode 100644
index 0000000000..9592c88146
--- /dev/null
+++ b/info/Blog/AllPosts.json
@@ -0,0 +1,34 @@
+{
+ "data": [
+ {
+ "title": "Compatibility of Apache DevLake with PostgreSQL",
+ "readTime": "3 min",
+ "authorName": "ZhangLiang",
+ "authorImgUrl":
"https://avatars.githubusercontent.com/u/8455907?s=400&v=4",
+ "publishTime": "2022/06/23",
+ "detailLink":
"/blog/compatibility-of-apache-devLake-with-postgreSQL",
+ "coverTitle": "compatibility-of-apache-devLake-with-postgreSQL",
+ "summary": "Apache DevLake is a dev data platform that can collect
and integrate data from different dev tools including Jira, Github, Gitlab and
Jenkins.This blog will not aim at a comprehensive summary of the compatibility
of database but a record of issues for future reference."
+ },
+ {
+ "title": "How DevLake is Up and Running",
+ "readTime": "4 min",
+ "authorName": "Warren Chen",
+ "authorImgUrl":
"https://avatars.githubusercontent.com/u/39366025?v=4",
+ "publishTime": "2022/06/17",
+ "detailLink": "/blog/how-DevLake-is-up-and-running",
+ "coverTitle": "How DevLake is up and running",
+ "summary": "Apache DevLake is an integration tool with the DevOps
data collection functionality, which presents a different stage of data to
development teams via Grafana. which also can leverage teams to improve the
development process with a data-driven model."
+ },
+ {
+ "title": "Apache Incubator Welcomes DevLake, A Dev-Data Platform
Serving Developers",
+ "readTime": "2 min",
+ "authorName": "Maxim Wheatley",
+ "authorImgUrl":
"https://avatars.githubusercontent.com/u/84928455?v=4",
+ "publishTime": "2022/05/18",
+ "detailLink": "/blog/apache-welcomes-devlake",
+ "coverTitle": "apache-welcomes-devLake",
+ "summary": "We are excited to share today that the Apache Software
Foundation (ASF) voted to make DevLake an officially supported project of the
Apache Incubator."
+ }
+ ]
+}
\ No newline at end of file
diff --git a/info/Blog/EditorPickBlog.json b/info/Blog/EditorPickBlog.json
new file mode 100644
index 0000000000..2b3fcd6c8a
--- /dev/null
+++ b/info/Blog/EditorPickBlog.json
@@ -0,0 +1,28 @@
+{
+ "data": [
+ {
+ "title": "How DevLake is Up and Running",
+ "readTime": "4 min",
+ "authorName": "Warren Chen",
+ "authorImgUrl":
"https://avatars.githubusercontent.com/u/39366025?v=4",
+ "publishTime": "2022/06/17",
+ "detailLink": "/blog/how-DevLake-is-up-and-running"
+ },
+ {
+ "title": "Apache Incubator Welcomes DevLake, A Dev-Data Platform
Serving Developers",
+ "readTime": "2 min",
+ "authorName": "Maxim Wheatley",
+ "authorImgUrl":
"https://avatars.githubusercontent.com/u/84928455?v=4",
+ "publishTime": "2022/05/18",
+ "detailLink": "/blog/apache-welcomes-devlake"
+ },
+ {
+ "title": "Compatibility of Apache DevLake with PostgreSQL",
+ "readTime": "3 min",
+ "authorName": "ZhangLiang",
+ "authorImgUrl":
"https://avatars.githubusercontent.com/u/8455907?s=400&v=4",
+ "publishTime": "2022/06/23",
+ "detailLink":
"/blog/compatibility-of-apache-devLake-with-postgreSQL"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 07d3d9aeef..ac133fbca6 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
"@docusaurus/plugin-content-docs": "^2.0.0-rc.1",
"@docusaurus/preset-classic": "^2.0.0-rc.1",
"@mdx-js/react": "^1.6.22",
+ "@tailwindcss/line-clamp": "^0.4.2",
"autoprefixer": "^10.4.8",
"clsx": "^1.1.1",
"dev-website-tailwind-config":
"github:merico-dev/dev-website-tailwind-config",
diff --git a/src/components/Blog/AllPosts.tsx b/src/components/Blog/AllPosts.tsx
new file mode 100644
index 0000000000..fe888e0fd2
--- /dev/null
+++ b/src/components/Blog/AllPosts.tsx
@@ -0,0 +1,102 @@
+import React from "react";
+import BlogInfo from "../../../info/Blog/AllPosts.json";
+import { BlogpageBottomBG } from './BlogpageBG';
+import { BlogInfoType } from "./types";
+import dateFormatter from "./utils";
+
+
+const ListItem = (props: { cardInfo: BlogInfoType }) => {
+ const { cardInfo } = props;
+ return (
+ <div
+ className="
+ flex flex-row-reverse mobile:flex-col-reverse
+ pb-[32px] mobile:pb-[24px]
+ border-neutral-100 border-[0] border-b-[2px] border-solid
+ "
+ >
+ <a href={cardInfo.detailLink}>
+ <img
+
src={require(`../../../static/img/Blog/${cardInfo.coverTitle}.png`).default}
+ className="
+ m-[auto] ml-[88px] sm:ml-[24px] mobile:ml-[0] mobile:mt-4
+ w-[400px] sm:w-[310px] mobile:w-[100%]
+ h-[225px] sm:h-[174px] mobile:h-[45.88vw]
+ bg-primary-300 rounded-[16px]"
+ />
+ </a>
+ <div
+ className="
+ flex flex-1 flex-col
+ "
+ >
+ <a href={cardInfo.detailLink} className="hover:no-underline">
+ <p
+ className="
+ text-primary-800 text-heading2 sm:text-heading4 font-semibold
+ line-clamp-2 m-[0] max-h-[60px] sm:max-h-[40px]"
+ >
+ {cardInfo.title}
+ </p>
+ </a>
+ <div
+ className="
+ text-neutral-300 text-label14Lake my-3
+ "
+ >
+ {`${dateFormatter(cardInfo.publishTime)} · ${cardInfo.readTime}`}
+ </div>
+ <p
+ className="
+ text-neutral-500 text-label18 sm:text-label16Lake
+ line-clamp-4 m-[0]
+ "
+ >
+ {cardInfo.summary}
+ </p>
+ <div className="mt-3 h-[50px] flex items-center">
+ <img
+ src={cardInfo.authorImgUrl}
+ className="w-[50px] h-[50px] mr-3 rounded-full bg-primary-500
shrink-0 uppercase flex justify-center items-center overflow-hidden text-white"
+ />
+ <span className="text-primary-800 text-heading4 font-semibold">
+ {cardInfo.authorName}
+ </span>
+ </div>
+ </div>
+ </div>
+ );
+};
+
+export function AllPosts() {
+ return (
+ <div className="relative">
+ <BlogpageBottomBG />
+ <div
+ className="
+ relative z-10
+ pt-[72px] pb-[80px] sm:pt-5 sm:pb-[60px] mobile:pt-4
+ "
+ >
+ <h2
+ className="
+ text-primary-800 text-heading1 sm:text-heading3 font-semibold
+ "
+ >
+ All Posts
+ </h2>
+ <div
+ className="
+ flex flex-col
+ mt-[65px] sm:mt-[32px] mobile:mt-[24px]
+ gap-5 mobile:gap-4
+ "
+ >
+ {BlogInfo.data.map((card: BlogInfoType) => (
+ <ListItem cardInfo={card} key={card.title} />
+ ))}
+ </div>
+ </div>
+ </div>
+ );
+}
diff --git a/src/components/Blog/BlogHeader.tsx
b/src/components/Blog/BlogHeader.tsx
new file mode 100644
index 0000000000..60543b9536
--- /dev/null
+++ b/src/components/Blog/BlogHeader.tsx
@@ -0,0 +1,19 @@
+import React from "react";
+
+export function BlogHeader() {
+ return (
+ <div className="mt-[80px] sm:mt-[32px] mobile:mt-[24px] mb-6 sm:mb-5
mobile:mb-4">
+ <h1 className="font-bold text-heading0 sm:text-heading2
text-primary-500">
+ Blog
+ </h1>
+ <div className="text-primary-800 text-label24 sm:text-label16Lake
mt-3">
+ <p className="m-[0]">
+ See what is happening with Apache DevLake.
+ </p>
+ <p className="m-[0]">
+ Gain insights into data-driven engineering from our passionate
developers.
+ </p>
+ </div>
+ </div>
+ );
+}
diff --git a/src/components/Blog/BlogpageBG.tsx
b/src/components/Blog/BlogpageBG.tsx
new file mode 100644
index 0000000000..a732ddce8d
--- /dev/null
+++ b/src/components/Blog/BlogpageBG.tsx
@@ -0,0 +1,71 @@
+import React from "react";
+import HeaderBGWS from "@site/static/img/Team/HeaderBG-ws.png";
+import HeaderBGTablet from "@site/static/img/Team/HeaderBG-tablet.png";
+import HeaderBGMobile from "@site/static/img/Team/HeaderBG-mobile.png";
+import BottomBGWS from '@site/static/img/Team/BottomBG-ws.png';
+import BottomBGTablet from '@site/static/img/Team/BottomBG-tablet.png';
+import BottomBGMobile from '@site/static/img/Team/BottomBG-mobile.png';
+
+export function BlogpageHeaderBG() {
+ return (
+ <div>
+ <>
+ <img
+ src={HeaderBGWS}
+ className="
+ absolute top-[0px] left-[0px]
+ h-[580px] w-screen
+ block sm:hidden
+ "
+ />
+ <img
+ src={HeaderBGTablet}
+ className="
+ absolute top-[0px] left-[0px]
+ h-[438px] w-screen
+ hidden sm:block mobile:hidden
+ "
+ />
+ <img
+ src={HeaderBGMobile}
+ className="
+ absolute top-[0px] left-[0px]
+ h-[456px] w-screen
+ hidden mobile:block
+ "
+ />
+ </>
+ </div>
+ );
+}
+
+export function BlogpageBottomBG() {
+ return (
+ <div>
+ <img
+ src={BottomBGWS}
+ className="
+ absolute top-[286px] left-[-15vw]
+ h-[1205px] min-w-[100vw]
+ block sm:hidden
+ "
+ />
+ <img
+ src={BottomBGTablet}
+ className="
+ absolute top-[210px] left-[-5vw]
+ h-[1663px] min-w-[100vw]
+ hidden sm:block mobile:hidden
+ "
+ />
+ <img
+ src={BottomBGMobile}
+ className="
+ absolute top-[24px] left-[-5vw]
+ h-[1768px] min-w-[100vw]
+ hidden mobile:block
+ "
+ />
+ </div>
+ )
+}
diff --git a/src/components/Blog/EditorPick.tsx
b/src/components/Blog/EditorPick.tsx
new file mode 100644
index 0000000000..3ca99c17e4
--- /dev/null
+++ b/src/components/Blog/EditorPick.tsx
@@ -0,0 +1,77 @@
+import React from "react";
+import BlogInfo from "../../../info/Blog/EditorPickBlog.json";
+import { BlogInfoType } from './types';
+import dateFormatter from "./utils";
+import apacheWelcomesDevLake from
'../../../static/img/Blog/apache-welcomes-devLake.png';
+import compatibilityOfApacheDevLakeWithPostgreSQL from
'../../../static/img/Blog/compatibility-of-apache-devLake-with-postgreSQL.png';
+import HowDevLakeIsUpAndRunning from '../../../static/img/Blog/How DevLake is
up and running.png';
+
+const coverImgArr = [HowDevLakeIsUpAndRunning, apacheWelcomesDevLake,
compatibilityOfApacheDevLakeWithPostgreSQL];
+const Card = function (props: {cardInfo: BlogInfoType, index: number}) {
+ const { cardInfo, index } = props;
+ return (
+ <a
+ href={cardInfo.detailLink}
+ className="flex flex-col sm:flex-row mobile:flex-col
+ w-[22.33vw] sm:max-w-[100%] sm:min-w-[100%]
+ p-[16px] bg-neutral-invert
+ rounded-[16px] shadow-lower hover:shadow-high hover:no-underline "
+ >
+ <img
+ src={coverImgArr[index]}
+ className="
+ w-[100%] sm:w-[43.05vw] sm:min-w-[43.05vw] mobile:w-[100%]
+ h-[12.76vw] sm:h-[24.21vw] mobile:h-[45.88vw]
+ bg-primary-300 rounded-[16px]"
+ />
+ <div className="sm:ml-5 mobile:ml-[0]">
+ <div className="flex h-[90px] sm:h-[60px] items-center mt-3 sm:mt-[0]
mb-3">
+ <p
+ className="
+ text-primary-800 text-heading2 sm:text-heading4 font-semibold
+ line-clamp-3 m-[0]
+ "
+ >
+ {cardInfo.title}
+ </p>
+ </div>
+ <div className="
+ text-neutral-300 text-label14Lake
+ ">
+ {`${dateFormatter(cardInfo.publishTime)} · ${cardInfo.readTime}`}
+ </div>
+ <div className="mt-3 h-[50px] flex items-center">
+ <img src={cardInfo.authorImgUrl} className="w-[50px] h-[50px] mr-3
rounded-full bg-primary-500 shrink-0 uppercase flex justify-center items-center
overflow-hidden text-white"
+ />
+ <span className="text-primary-800 text-heading4 font-semibold">
+ {cardInfo.authorName}
+ </span>
+ </div>
+ </div>
+ </a>
+ );
+};
+
+export function EditorPick() {
+ return (
+ <div>
+ <h2
+ className="
+ text-primary-800 text-heading1 sm:text-heading3 font-semibold
+ mt-[60px] sm:mt-[32px] mobile:mt-[20px]
+ "
+ >
+ Editor‘s Picks
+ </h2>
+ <div className="
+ flex sm:flex-col justify-between
+ mt-[64px] sm:mt-[32px] mobile:mt-[24px]
+ sm:gap-5 mobile:gap-4
+ ">
+ {BlogInfo.data.map((card: BlogInfoType, index:number) => (
+ <Card cardInfo ={card} key={card.title} index={index}/>
+ ))}
+ </div>
+ </div>
+ );
+}
diff --git a/src/components/Blog/types.ts b/src/components/Blog/types.ts
new file mode 100644
index 0000000000..71b6363953
--- /dev/null
+++ b/src/components/Blog/types.ts
@@ -0,0 +1,10 @@
+export interface BlogInfoType {
+ title: string,
+ readTime: string,
+ authorName: string,
+ authorImgUrl: string,
+ publishTime: string,
+ detailLink: string,
+ summary?: string,
+ coverTitle: string
+ }
\ No newline at end of file
diff --git a/src/components/Blog/utils.tsx b/src/components/Blog/utils.tsx
new file mode 100644
index 0000000000..d284057cb3
--- /dev/null
+++ b/src/components/Blog/utils.tsx
@@ -0,0 +1,21 @@
+const dateMapper = {
+ '01': 'Jan',
+ '02': 'Feb',
+ '03': 'Mar',
+ '04': 'Apr',
+ '05': 'May',
+ '06': 'Jun',
+ '07': 'Jul',
+ '08': 'Aug',
+ '09': 'Sept',
+ '10': 'Oct',
+ '11': 'Nov',
+ '12': 'Dec'
+ }
+
+ function dateFormatter(date: string) {
+ const [year, month, day] = date.split('/');
+ return `${dateMapper[month]} ${day}, ${year}`;
+ }
+
+export default dateFormatter;
\ No newline at end of file
diff --git a/src/pages/blogOverview/index.js b/src/pages/blogOverview/index.js
new file mode 100644
index 0000000000..c3e28e02c4
--- /dev/null
+++ b/src/pages/blogOverview/index.js
@@ -0,0 +1,31 @@
+import React from 'react';
+import Layout from '@theme/Layout';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import { BlogpageHeaderBG, BlogpageBottomBG } from
'@site/src/components/Blog/BlogpageBG';
+import { BlogHeader } from '@site/src/components/Blog/BlogHeader';
+import { EditorPick } from '@site/src/components/Blog/EditorPick';
+import { AllPosts } from '@site/src/components/Blog/AllPosts';
+
+export default function BlogOverview() {
+ const { siteConfig } = useDocusaurusContext();
+ return (
+ <Layout
+ title={`${siteConfig.title}`}
+ description="Apache DevLake is an open-source dev data platform that
ingests, analyzes, and visualizes the fragmented data from DevOps tools to
distill insights for engineering productivity.">
+ <div className='bg-[#f8f8f8]'>
+ <div className='mx-auto bg-white max-w-[100vw] overflow-hidden
relative'>
+ <BlogpageHeaderBG />
+ <main
+ className='
+ text-start w-[70%] max-w-[1200px] sm:w-[90%]
+ relative mx-auto min-h-[800px]
+ '>
+ <BlogHeader />
+ <EditorPick />
+ <AllPosts />
+ </main>
+ </div>
+ </div>
+ </Layout>
+ );
+}
diff --git a/static/img/Blog/How DevLake is up and running.png
b/static/img/Blog/How DevLake is up and running.png
new file mode 100644
index 0000000000..e75f4b3f62
Binary files /dev/null and b/static/img/Blog/How DevLake is up and running.png
differ
diff --git a/static/img/Blog/apache-welcomes-devLake.png
b/static/img/Blog/apache-welcomes-devLake.png
new file mode 100644
index 0000000000..637613838e
Binary files /dev/null and b/static/img/Blog/apache-welcomes-devLake.png differ
diff --git
a/static/img/Blog/compatibility-of-apache-devLake-with-postgreSQL.png
b/static/img/Blog/compatibility-of-apache-devLake-with-postgreSQL.png
new file mode 100644
index 0000000000..3f64fc086a
Binary files /dev/null and
b/static/img/Blog/compatibility-of-apache-devLake-with-postgreSQL.png differ
diff --git a/tailwind.config.js b/tailwind.config.js
index d806c54410..a22c159234 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -6,8 +6,12 @@ tailwindConfig.theme.extend.fontSize = {
label40: ['40px', { lineHeight : '56px' }],
label20: ['20px', { lineHeight: '30px' }],
label12: ['12px', { lineHeight: '15px' }],
+ label14Lake: ['14px', { lineHeight: '17px' }],
label16Lake: ['16px', { lineHeight: '22px' }]
}
+tailwindConfig.plugins = [
+ require('@tailwindcss/line-clamp'),
+];
module.exports = tailwindConfig;
// pre config