Skip to content
This repository was archived by the owner on Feb 2, 2025. It is now read-only.

Commit c8b2681

Browse files
authored
Merge pull request #62 from SystemEngineeringTeam/feat-events-page
イベントページ追加
2 parents e7c7fe7 + beba4f8 commit c8b2681

File tree

9 files changed

+322
-2
lines changed

9 files changed

+322
-2
lines changed

Diff for: app/events/[id]/page.tsx

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { getEvents } from '@/components/loadFiles';
2+
import Md2Html from '@/components/md2html';
3+
import { css } from '@/styled-system/css';
4+
import { mdStyle } from '@/styled-system/patterns';
5+
6+
export const generateStaticParams = () => {
7+
const events = getEvents();
8+
9+
return events.map((e) => ({
10+
id: e.id.toString(),
11+
}));
12+
};
13+
14+
type Props = {
15+
params: {
16+
id: string;
17+
};
18+
};
19+
20+
export default function Products(props: Props) {
21+
const {
22+
params: { id },
23+
} = props;
24+
25+
const events = getEvents();
26+
const event = events.find((event) => event.id.toString() === id);
27+
28+
if (event === undefined) throw new Error('Event not found');
29+
30+
return (
31+
<main
32+
className={css({
33+
padding: '80px 20px',
34+
})}
35+
>
36+
<div
37+
className={css({
38+
marginInline: 'auto',
39+
width: '100%',
40+
maxWidth: '800px',
41+
})}
42+
>
43+
<h1
44+
className={css({
45+
fontSize: '2rem',
46+
fontWeight: 700,
47+
marginBottom: '1rem',
48+
borderBottom: '1px solid black',
49+
})}
50+
>
51+
{event?.meta.title}
52+
</h1>
53+
54+
<section>
55+
<Md2Html
56+
className={mdStyle({
57+
style: 'default',
58+
})}
59+
content={event?.content}
60+
/>
61+
</section>
62+
</div>
63+
</main>
64+
);
65+
}

Diff for: app/events/_components/_components/Card.tsx

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
'use client';
2+
3+
import { useRouter } from 'next/navigation';
4+
import Md2Html from '@/components/md2html';
5+
import { formatdate } from '@/components/util';
6+
import { css } from '@/styled-system/css';
7+
import { mdStyle } from '@/styled-system/patterns';
8+
import { EventPage } from '@/types';
9+
10+
interface Props {
11+
event: EventPage;
12+
}
13+
14+
export default function EventCard(props: Props) {
15+
const { event } = props;
16+
const router = useRouter();
17+
18+
const now = Date.now();
19+
20+
function jumpTo() {
21+
router.push(`/events/${event.id}`);
22+
}
23+
24+
return (
25+
<div
26+
className={css({
27+
height: '300px',
28+
padding: '20px',
29+
textAlign: 'start',
30+
boxShadow: '4px 2px 10px -5px #777777',
31+
borderRadius: '5px',
32+
overflow: 'hidden',
33+
transition: 'scale 0.2s',
34+
cursor: 'pointer',
35+
36+
'&:hover': {
37+
scale: 1.02,
38+
},
39+
})}
40+
onClick={jumpTo}
41+
// 期限が過ぎたお知らせは非表示
42+
style={{ display: now < event.deadline.getTime() ? 'block' : 'none' }}
43+
>
44+
<p>
45+
{formatdate(event.meta.created_at)} - {formatdate(event.deadline)}
46+
</p>
47+
48+
<h3
49+
className={css({
50+
paddingBottom: '10px',
51+
fontSize: '1.5rem',
52+
fontWeight: 'bold',
53+
overflow: 'hidden',
54+
textWrap: 'nowrap',
55+
textOverflow: 'ellipsis',
56+
})}
57+
>
58+
{event.meta.title}
59+
</h3>
60+
61+
<div
62+
className={css({
63+
height: '195px',
64+
overflow: 'hidden',
65+
overflowWrap: 'break-word',
66+
})}
67+
>
68+
<Md2Html
69+
className={mdStyle({
70+
style: 'no-style',
71+
})}
72+
content={event.overview}
73+
/>
74+
</div>
75+
</div>
76+
);
77+
}

Diff for: app/events/_components/_components/List.tsx

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import EventCard from './Card';
2+
import { css } from '@/styled-system/css';
3+
import { EventPage } from '@/types';
4+
5+
interface Props {
6+
events: EventPage[];
7+
}
8+
9+
export default function EventList(props: Props) {
10+
const { events } = props;
11+
12+
return (
13+
<section
14+
className={css({
15+
display: 'grid',
16+
gap: '20px',
17+
gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))',
18+
})}
19+
>
20+
{events.map((event) => (
21+
<EventCard key={event.id} event={event} />
22+
))}
23+
</section>
24+
);
25+
}

Diff for: app/events/page.tsx

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import EventList from './_components/_components/List';
2+
import { getEvents } from '@/components/loadFiles';
3+
import { css } from '@/styled-system/css';
4+
5+
export default function EventsPage() {
6+
const events = getEvents();
7+
8+
return (
9+
<main
10+
className={css({
11+
padding: '80px 20px',
12+
maxWidth: '1000px',
13+
marginInline: 'auto',
14+
})}
15+
>
16+
<h1
17+
className={css({
18+
fontSize: '2rem',
19+
fontWeight: 700,
20+
marginBottom: '1rem',
21+
borderBottom: '1px solid black',
22+
})}
23+
>
24+
募集中のイベント
25+
</h1>
26+
<EventList events={events} />
27+
</main>
28+
);
29+
}

Diff for: components/loadFiles.ts

+54-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import fs from 'fs';
22
import path from 'path';
33
import matter from 'gray-matter';
44
import { IMAGE_REGEX } from '@/const';
5-
import { Page, Image, PostPage, Product, NoticePage } from '@/types';
5+
import { Page, Image, PostPage, Product, NoticePage, EventPage } from '@/types';
66

77
export function getTopImages(): Image[] {
88
const imagesDir = path.join(process.cwd(), 'public/img/top');
@@ -35,6 +35,59 @@ function parseMetaTag(
3535
return defaultValue;
3636
}
3737

38+
export function getEvents(): EventPage[] {
39+
const contentsDir = path.join(process.cwd(), 'public/markdown/events');
40+
const filenames = fs.readdirSync(contentsDir);
41+
const filteredFilenames = filenames.filter(
42+
(filename) => !filename.startsWith('.'),
43+
);
44+
45+
const pages: EventPage[] = filteredFilenames.map((filename) => {
46+
const filePath = path.join(contentsDir, filename);
47+
const fileContents = fs.readFileSync(filePath, 'utf8');
48+
const md = matter(fileContents);
49+
const meta = md.data;
50+
51+
if (typeof meta.tags === 'string') meta.tags = meta.tags.split(', ');
52+
53+
const createdAt = parseMetaTag(
54+
meta.tags,
55+
'at',
56+
meta.created_at,
57+
/\d{4}-\d{2}-\d{2}/,
58+
);
59+
meta.created_at = new Date(createdAt);
60+
61+
const deadline = parseMetaTag(
62+
meta.tags,
63+
'deadline',
64+
'3000-01-01',
65+
/\d{4}-\d{2}-\d{2}/,
66+
);
67+
68+
const overview = md.content.split('---').at(0) || '';
69+
const content = md.content.includes('---')
70+
? md.content.split('---').slice(1).join('---')
71+
: md.content;
72+
73+
return {
74+
filename,
75+
deadline: deadline ? new Date(deadline) : null,
76+
id: md.data.number,
77+
meta,
78+
content,
79+
overview,
80+
} as EventPage;
81+
});
82+
83+
const filteredPosts = pages.filter((page) => page.meta.title !== 'README');
84+
filteredPosts.sort((a, b) =>
85+
a.meta.created_at > b.meta.created_at ? -1 : 1,
86+
);
87+
88+
return filteredPosts;
89+
}
90+
3891
export function getNotices(): NoticePage[] {
3992
const contentsDir = path.join(process.cwd(), 'public/markdown/notice');
4093
const filenames = fs.readdirSync(contentsDir);

Diff for: const/index.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@ export const mdStyles = [
55
'a-only',
66
] as const;
77

8-
export const specialPath = ['/', '/posts', '/post', '/products', '/dev'];
8+
export const specialPath = [
9+
'/',
10+
'/posts',
11+
'/post',
12+
'/products',
13+
'/dev',
14+
'/events',
15+
];
916

1017
export const DEFAULT_POST_THUMBNAIL = '/img/posts/default.webp';
1118
export const DEFAULT_PRODUCT_THUMBNAIL = '/img/products/default.webp';

Diff for: public/markdown/events/1288.html.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
title: asdfasdfasdf
3+
category:
4+
tags: at:2024-03-18, deadline:2024-09-18, category:イベント
5+
created_at: '2024-03-18T17:42:22+09:00'
6+
updated_at: '2024-03-18T18:50:51+09:00'
7+
published: true
8+
number: 1288
9+
---
10+
11+
ここに概要が入ります
12+
13+
---
14+
15+
# アクセス
16+
愛知工業大学 八草キャンパス 4号館別館 3階 310が部室です。
17+
18+
正門近くの1号館から歩いて約10分程です。
19+
20+
現在は4号館別館が部室のある棟ですが、近々この棟はなくなるので2年後くらいに部室の引っ越しをします。1号館近くに引っ越しになる予定です。
21+
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2229.702625338343!2d137.11433052322164!3d35.184538944361755!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x6003670d681bdf13%3A0x8dd4ff9bff0cfb7e!2z77yU5Y-36aSo5Yil6aSo!5e0!3m2!1sja!2sjp!4v1698985780113!5m2!1sja!2sjp" width="600" height="450" style="border:0;" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>
22+
23+
24+
# 部室への行き方
25+
具体的な部室への行き方です。
26+
27+
### 1.ここが4号館別館です。
28+
正門近くの1号館から歩いて約10分程です。
29+
<img width="1280" alt="image.png (1.2 MB)" src="/img/markdown/762/b06ccc9b-50ea-49de-90cf-c89e48a77179.webp">
30+
31+
### 2.部室は3階にあります。
32+
33+
3階まで階段を登ったら右側に進みます。
34+
<img width="1280" alt="image.png (879.5 kB)" src="/img/markdown/762/216dd883-2303-4ec0-9951-cbbbbd733727.webp">
35+
36+
### 3.右側の廊下を一番奥まで進みます。
37+
38+
<img width="1280" alt="image.png (796.3 kB)" src="/img/markdown/762/d6f12f08-aff4-4b4b-9b4a-fa4dfe1bc4ef.webp">
39+
40+
### 4.システム工学研究会の張り紙がしてある部屋がシス研の部室です。
41+
<img width="1280" alt="image.png (646.5 kB)" src="/img/markdown/762/d57343b6-8ba9-4f93-8e94-426823112b37.webp">
42+

Diff for: public/markdown/events/1326.html.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
title: 入部希望者へのお知らせ
3+
category:
4+
tags: at:2024-04-05, deadline:2024-06-31, category:お知らせ
5+
created_at: '2024-04-05T12:48:36+09:00'
6+
updated_at: '2024-04-10T18:29:11+09:00'
7+
published: true
8+
number: 1326
9+
---
10+
11+
入部希望の方は 部室[4号館別館310](https://www.sysken.net/access) までお願いします!基本的に毎日空いているのでいつでも来てください。
12+
何か質問等は [X(Twitter)](https://twitter.com/set_official )もしくは [instagram](https://www.instagram.com/ait.sysken?igsh=aDc4MWFnbWJ1bjY1&utm_source=qr )のDMで待ってます
13+
詳細は [入部の手引き](http://localhost:3000/newcomer) を参考にしてください
14+

Diff for: types/index.ts

+8
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ export type NoticePage = Omit<
3333
deadline: Date;
3434
};
3535

36+
export type EventPage = Omit<
37+
Page,
38+
'path' | 'style' | 'widthNarrow' | 'other' | 'sort'
39+
> & {
40+
deadline: Date;
41+
overview: string;
42+
};
43+
3644
export type Product = {
3745
title: string;
3846
created_at: Date;

0 commit comments

Comments
 (0)