Skip to content

Commit c2c7cf5

Browse files
authored
add post list (#51)
1 parent 204ab1f commit c2c7cf5

File tree

10 files changed

+230
-9
lines changed

10 files changed

+230
-9
lines changed
Lines changed: 1 addition & 0 deletions
Loading

app/content/posts/personal-website/dagger-io/dagger-io.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
nanoId: qs05qpu3c0p78ww123zv1
33
title: How I added dagger.io to my personal website
44
date: 2024-04-18
5-
wip: true
5+
thumb: ./assets/dagger-logo.svg
66
---
77

88
import { PostImage as Image } from "@/components/molecues/post-image";
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
1+
import Box from "@mui/material/Box";
12
import * as React from "react";
23

3-
import { Wip } from "@/components/organisms/wip";
4+
import { PostItem, PostItemProps } from "@/components/organisms/post-item";
45
import { MainTemplate, MainTemplateProps } from "@/components/templates/main";
56

67
export type HomeFrameProps = {
78
mainTemplateProps: MainTemplateProps;
9+
posts: PostItemProps[];
810
};
911

10-
export const HomeFrame = ({ mainTemplateProps }: HomeFrameProps) => {
12+
export const HomeFrame = ({ mainTemplateProps, posts }: HomeFrameProps) => {
1113
return (
1214
<MainTemplate {...mainTemplateProps}>
13-
<Wip />
15+
<Box>
16+
<Box>
17+
{posts.map((post) => (
18+
<PostItem key={post.link} {...post} />
19+
))}
20+
</Box>
21+
</Box>
1422
</MainTemplate>
1523
);
1624
};

app/src/components/organisms/app-header/index.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export const AppHeader = ({
4040
variant="h6"
4141
underline="none"
4242
to="/"
43+
aria-label="Home"
4344
>
4445
ndthanhdev
4546
</Link>
@@ -48,6 +49,7 @@ export const AppHeader = ({
4849
variant="text"
4950
size="large"
5051
to="/about"
52+
aria-label="About"
5153
>
5254
about
5355
</Button>
@@ -56,6 +58,7 @@ export const AppHeader = ({
5658
variant="text"
5759
size="large"
5860
to="/projects"
61+
arial-label="Projects"
5962
>
6063
Projects
6164
</Button>
@@ -66,14 +69,20 @@ export const AppHeader = ({
6669
edge="end"
6770
color="primary"
6871
onClick={onToggleThemeMode}
72+
area-label="Toggle theme mode"
6973
>
7074
{themeMode === ThemeMode.Light ? (
7175
<LightModeOutlinedIcon />
7276
) : (
7377
<DarkModeOutlinedIcon />
7478
)}
7579
</IconButton>
76-
<IconButton color="primary" size="large" onClick={onOpenSettings}>
80+
<IconButton
81+
color="primary"
82+
size="large"
83+
onClick={onOpenSettings}
84+
aria-label="Open settings"
85+
>
7786
<MenuOutlinedIcon />
7887
</IconButton>
7988
</Stack>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import ArticleOutlinedIcon from "@mui/icons-material/ArticleOutlined";
2+
import Box from "@mui/material/Box";
3+
import Divider from "@mui/material/Divider";
4+
import Link from "@mui/material/Link";
5+
import Typography from "@mui/material/Typography";
6+
import { Link as GatsbyLink } from "gatsby";
7+
import { DateTime } from "luxon";
8+
import * as React from "react";
9+
10+
import { styles } from "./styles";
11+
12+
export type PostItemProps = {
13+
title?: string;
14+
link: string;
15+
date?: string;
16+
excerpt?: string;
17+
thumb?: string;
18+
};
19+
20+
export const PostItem = ({
21+
thumb,
22+
title,
23+
date: dateProp,
24+
link,
25+
excerpt,
26+
}: PostItemProps) => {
27+
const date = dateProp
28+
? DateTime.fromISO(dateProp).toLocaleString(DateTime.DATE_FULL)
29+
: "";
30+
31+
return (
32+
<Box css={styles.root}>
33+
<Link
34+
component={GatsbyLink}
35+
to={link}
36+
underline="none"
37+
css={styles.title}
38+
variant="h6"
39+
>
40+
{title}
41+
</Link>
42+
<Typography css={styles.date} variant="subtitle1">
43+
{date}
44+
</Typography>
45+
<Link
46+
component={GatsbyLink}
47+
to="/posts/qs05qpu3c0p78ww123zv1/"
48+
underline="none"
49+
css={styles.description}
50+
variant="body1"
51+
>
52+
{excerpt}
53+
</Link>
54+
{thumb ? (
55+
<img css={styles.thumb} alt="post thumbnail" src={thumb} />
56+
) : (
57+
<ArticleOutlinedIcon css={styles.thumb} />
58+
)}
59+
<Divider css={styles.divider} />
60+
</Box>
61+
);
62+
};
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { css } from "@emotion/react";
2+
3+
import { AppTheme } from "@/theme";
4+
import { lineClamp } from "@/utils/styles/line-clamp";
5+
6+
const Constants = {
7+
titleLineCount: 2,
8+
descLineCount: 2,
9+
};
10+
11+
export const styles = {
12+
root: (theme: AppTheme) =>
13+
css({
14+
display: "grid",
15+
gridTemplateColumns: `1fr auto auto`,
16+
gridTemplateRows: "auto auto minmax(0, 1fr) auto",
17+
gridTemplateAreas: `\
18+
"title . thumb"
19+
"date . thumb"
20+
"description . thumb"
21+
"divider divider divider"
22+
`,
23+
marginBlockStart: theme.spacing(4),
24+
marginBlockEnd: theme.spacing(2),
25+
height: theme.spacing(20),
26+
[theme.breakpoints.down("md")]: {
27+
height: theme.spacing(22),
28+
},
29+
overflow: "hidden",
30+
}),
31+
32+
title: (theme: AppTheme) =>
33+
css({
34+
gridArea: "title",
35+
marginInlineEnd: theme.spacing(2),
36+
color: theme.palette.text.primary,
37+
...lineClamp(
38+
Constants.titleLineCount,
39+
theme.typography.h6.fontSize!,
40+
theme.typography.h6.lineHeight!,
41+
),
42+
}),
43+
44+
date: css({
45+
gridArea: "date",
46+
}),
47+
48+
description: (theme: AppTheme) =>
49+
css({
50+
gridArea: "description",
51+
marginBlockStart: theme.spacing(2),
52+
marginInlineEnd: theme.spacing(2),
53+
color: theme.palette.text.secondary,
54+
...lineClamp(
55+
Constants.descLineCount,
56+
theme.typography.body1.fontSize!,
57+
theme.typography.body1.lineHeight!,
58+
),
59+
}),
60+
61+
thumb: (theme: AppTheme) =>
62+
css({
63+
gridArea: "thumb",
64+
width: theme.spacing(15),
65+
height: theme.spacing(15),
66+
objectFit: "cover",
67+
objectPosition: "center",
68+
backgroundColor: theme.palette.augmentColor({
69+
color: {
70+
main: theme.palette.background.paper,
71+
},
72+
}).light,
73+
}),
74+
75+
divider: (theme: AppTheme) =>
76+
css({
77+
gridArea: "divider",
78+
paddingBlockStart: theme.spacing(2),
79+
}),
80+
};

app/src/gatsby-types.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,6 +1342,7 @@ type MdxFilterListInput = {
13421342
type MdxFrontmatter = {
13431343
readonly date: Maybe<Scalars['Date']>;
13441344
readonly nanoId: Maybe<Scalars['String']>;
1345+
readonly thumb: Maybe<File>;
13451346
readonly title: Maybe<Scalars['String']>;
13461347
readonly wip: Maybe<Scalars['Boolean']>;
13471348
};
@@ -1357,20 +1358,23 @@ type MdxFrontmatter_dateArgs = {
13571358
type MdxFrontmatterFieldSelector = {
13581359
readonly date: InputMaybe<FieldSelectorEnum>;
13591360
readonly nanoId: InputMaybe<FieldSelectorEnum>;
1361+
readonly thumb: InputMaybe<FileFieldSelector>;
13601362
readonly title: InputMaybe<FieldSelectorEnum>;
13611363
readonly wip: InputMaybe<FieldSelectorEnum>;
13621364
};
13631365

13641366
type MdxFrontmatterFilterInput = {
13651367
readonly date: InputMaybe<DateQueryOperatorInput>;
13661368
readonly nanoId: InputMaybe<StringQueryOperatorInput>;
1369+
readonly thumb: InputMaybe<FileFilterInput>;
13671370
readonly title: InputMaybe<StringQueryOperatorInput>;
13681371
readonly wip: InputMaybe<BooleanQueryOperatorInput>;
13691372
};
13701373

13711374
type MdxFrontmatterSortInput = {
13721375
readonly date: InputMaybe<SortOrderEnum>;
13731376
readonly nanoId: InputMaybe<SortOrderEnum>;
1377+
readonly thumb: InputMaybe<FileSortInput>;
13741378
readonly title: InputMaybe<SortOrderEnum>;
13751379
readonly wip: InputMaybe<SortOrderEnum>;
13761380
};
@@ -2589,6 +2593,11 @@ type GatsbyImageSharpFluid_withWebp_tracedSVGFragment = { readonly tracedSVG: st
25892593

25902594
type GatsbyImageSharpFluidLimitPresentationSizeFragment = { readonly maxHeight: number, readonly maxWidth: number };
25912595

2596+
type HomeQueryVariables = Exact<{ [key: string]: never; }>;
2597+
2598+
2599+
type HomeQuery = { readonly allMdx: { readonly nodes: ReadonlyArray<{ readonly id: string, readonly excerpt: string | null, readonly frontmatter: { readonly title: string | null, readonly nanoId: string | null, readonly date: string | null, readonly thumb: { readonly publicURL: string | null } | null } | null }> } };
2600+
25922601
type MyCVQueryQueryVariables = Exact<{
25932602
id: Scalars['String'];
25942603
}>;

app/src/layouts/cv/index.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ import * as React from "react";
33
import { Merge } from "type-fest";
44

55
import { MyHelmet } from "@/components/atoms/my-helmet";
6+
import { CVTemplate } from "@/components/templates/cv";
67
import { AppMDXProvider } from "@/providers/mdx-provider";
78
import { AppThemeProvider } from "@/providers/theme-provider";
89
import { ThemeMode } from "@/theme";
910

10-
import { CVTemplate } from "../../components/templates/cv";
11-
1211
export type MyCVTemplateProps = Merge<
1312
PageProps<Queries.MyCVQueryQuery>,
1413
React.PropsWithChildren<object>

app/src/pages/index.tsx

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,51 @@
1+
import { graphql, PageProps } from "gatsby";
12
import * as React from "react";
23

34
import { HomeFrame } from "@/components/frames/home";
5+
import { PostItemProps } from "@/components/organisms/post-item";
46
import { useMainTemplateProps } from "@/hooks/use-main-template-props";
57

6-
function HomePage() {
8+
export type HomePageProps = PageProps<Queries.HomeQuery>;
9+
10+
function HomePage({ data }: HomePageProps) {
711
const mainTemplateProps = useMainTemplateProps();
812

9-
return <HomeFrame mainTemplateProps={mainTemplateProps} />;
13+
const posts = data.allMdx?.nodes?.map((post) => {
14+
return {
15+
link: `/posts/${post.frontmatter?.nanoId}`,
16+
title: post.frontmatter?.title,
17+
date: post.frontmatter?.date,
18+
excerpt: post.excerpt,
19+
thumb: post.frontmatter?.thumb?.publicURL,
20+
} as PostItemProps;
21+
});
22+
23+
return <HomeFrame mainTemplateProps={mainTemplateProps} posts={posts} />;
1024
}
1125

1226
export default HomePage;
27+
28+
export const pageQuery = graphql`
29+
query Home {
30+
allMdx(
31+
filter: {
32+
frontmatter: { wip: { ne: true } }
33+
internal: { contentFilePath: { glob: "**/posts/**" } }
34+
}
35+
sort: { frontmatter: { date: DESC } }
36+
) {
37+
nodes {
38+
id
39+
frontmatter {
40+
title
41+
nanoId
42+
date
43+
thumb {
44+
publicURL
45+
}
46+
}
47+
excerpt
48+
}
49+
}
50+
}
51+
`;

app/src/utils/styles/line-clamp.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { CSSObject } from "@emotion/css";
2+
3+
export const lineClamp = (
4+
lineCount: number,
5+
fontSize: string | number,
6+
lineHeight: string | number,
7+
): CSSObject => ({
8+
display: "-webkit-box",
9+
WebkitLineClamp: lineCount,
10+
WebkitBoxOrient: "vertical",
11+
overflow: "hidden",
12+
textOverflow: "ellipsis",
13+
maxHeight: `calc(${fontSize} * ${lineHeight} * ${lineCount})`,
14+
});

0 commit comments

Comments
 (0)