Skip to content

Commit 9b2fd18

Browse files
feat: staff (#930)
* feat: add staff grid components and i18n labels * feat: add core staff info * feat: add leader section and fix styles * fix: x link and image paths * feat: add volunteer, minimize images * chore: add staff name to cSpell * fix: linter * chore: optimize image sizes * fix: layout * chore: add feature flags * save * save * save * save * save * save * save --------- Co-authored-by: ubugeeei <ubuge1122@gmail.com>
1 parent 5733802 commit 9b2fd18

File tree

116 files changed

+827
-3
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+827
-3
lines changed

app/constant.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const HOME_HEADING_ID = {
1212
access: "access",
1313
studentSupport: "student-support",
1414
store: "store",
15+
staff: "staff",
1516

1617
// NOTE: Be careful as it is hardcoded in MDC
1718
contact: "contact-form",
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<script setup lang="ts">
2+
import { HOME_HEADING_ID } from "~/constant";
3+
import { useI18n, useFetch, useBreakpoint, computed } from "#imports";
4+
import { VFSection } from "#components";
5+
6+
import StaffGrid from "./StaffGrid.vue";
7+
8+
const { t } = useI18n();
9+
const bp = useBreakpoint();
10+
11+
const { data: staffList } = await useFetch("/api/staffs");
12+
13+
const leaderColumns = computed(() => {
14+
return bp.value === "pc" ? 3 : 2;
15+
});
16+
17+
const coreColumns = computed(() => {
18+
return bp.value === "pc" ? 4 : 3;
19+
});
20+
</script>
21+
22+
<template>
23+
<VFSection :id="HOME_HEADING_ID.staff" :title="t('staff.title')">
24+
<p class="staff-description">
25+
{{ t('staff.description') }}
26+
</p>
27+
<template v-if="staffList">
28+
<StaffGrid
29+
:staff-list="staffList.leaders"
30+
grid-mode="leader"
31+
:columns="leaderColumns"
32+
/>
33+
<StaffGrid
34+
:staff-list="staffList.cores"
35+
grid-mode="core"
36+
:columns="coreColumns"
37+
/>
38+
39+
<VFHeading id="volunteer-staff">
40+
{{ t('staff.volunteer') }}
41+
</VFHeading>
42+
43+
<StaffGrid
44+
:staff-list="staffList.volunteers"
45+
grid-mode="volunteer"
46+
/>
47+
</template>
48+
</VFSection>
49+
</template>
50+
51+
<style scoped>
52+
.staff-description {
53+
margin: 2rem 0;
54+
word-break: break-all;
55+
}
56+
</style>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<script setup lang="ts">
2+
import { computed } from "vue";
3+
4+
import StaffGridItem, { type StaffItemProps } from "./StaffGridItem.vue";
5+
6+
const {
7+
staffList,
8+
gridMode,
9+
columns,
10+
} = defineProps<{
11+
staffList: StaffItemProps[];
12+
gridMode: "leader" | "core" | "volunteer";
13+
columns?: number;
14+
}>();
15+
16+
const gridClass = computed(() => `staff-grid staff-grid-${gridMode}`);
17+
18+
const gridStyle = computed(() =>
19+
columns && (gridMode === "leader" || gridMode === "core")
20+
? { gridTemplateColumns: `repeat(${columns}, 1fr)` }
21+
: {},
22+
);
23+
</script>
24+
25+
<template>
26+
<div :class="gridClass" :style="gridStyle">
27+
<StaffGridItem
28+
v-for="(staff, idx) in staffList" :key="idx" class="staff-member"
29+
v-bind="{ ...staff, gridMode }"
30+
/>
31+
</div>
32+
</template>
33+
34+
<style scoped>
35+
@import "~/assets/styles/custom-media-query.css";
36+
37+
.staff-grid {
38+
display: grid;
39+
margin-bottom: 1.5rem;
40+
}
41+
42+
.staff-grid-leader {
43+
gap: 1rem;
44+
}
45+
46+
.staff-grid-core {
47+
gap: 0.9rem;
48+
}
49+
50+
.staff-grid-volunteer {
51+
display: flex;
52+
flex-wrap: wrap;
53+
align-items: left;
54+
margin: 1.5rem 0 0 0;
55+
}
56+
</style>
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<script lang="ts">
2+
import { computed } from "vue";
3+
4+
export type StaffItemProps = {
5+
name: string;
6+
avatarUrl: string;
7+
socialUrls?: {
8+
x?: string;
9+
github?: string;
10+
};
11+
};
12+
</script>
13+
14+
<script setup lang="ts">
15+
const {
16+
name,
17+
avatarUrl,
18+
socialUrls,
19+
gridMode,
20+
} = defineProps<StaffItemProps & { gridMode: "leader" | "core" | "volunteer" }>();
21+
22+
const gridItemClass = computed(() => `staff-link-${gridMode}`);
23+
24+
const linkComp = computed(() => socialUrls?.x ? socialUrls.x : socialUrls?.github);
25+
</script>
26+
27+
<template>
28+
<NuxtLink
29+
v-if="linkComp"
30+
:to="linkComp"
31+
external
32+
target="_blank"
33+
class="staff"
34+
:class="gridItemClass"
35+
>
36+
<img :src="avatarUrl" :alt="name" />
37+
<p class="font-bold">{{ name }}</p>
38+
</NuxtLink>
39+
40+
<div v-else class="staff" :class="gridItemClass">
41+
<img v-if="avatarUrl" :src="avatarUrl" :alt="name" loading="lazy" />
42+
<p class="font-bold">
43+
{{ name }}
44+
</p>
45+
</div>
46+
</template>
47+
48+
<style scoped>
49+
@import "~/assets/styles/custom-media-query.css";
50+
51+
.staff {
52+
display: flex;
53+
flex-direction: column;
54+
align-items: center;
55+
text-decoration: none;
56+
color: #444;
57+
margin-bottom: 1rem;
58+
59+
p {
60+
width: 100%;
61+
text-align: left;
62+
overflow-wrap: break-word;
63+
color: var(--color-text-default);
64+
margin-top: 1rem;
65+
66+
@media (--mobile) {
67+
margin-top: 0.75rem;
68+
}
69+
}
70+
71+
&.staff-link-leader,
72+
&.staff-link-core {
73+
p {
74+
font-size: 18px;
75+
font-family: IBMPlexSansJP-Bold;
76+
77+
@media (--mobile) {
78+
font-size: 16px;
79+
}
80+
}
81+
82+
img {
83+
width: 100%;
84+
height: auto;
85+
border-radius: 8%;
86+
border: 0.5px solid #ddd;
87+
}
88+
}
89+
90+
&.staff-link-volunteer {
91+
margin-bottom: 0;
92+
93+
p {
94+
margin: 0.3rem 0.6rem;
95+
text-align: left;
96+
97+
@media (--mobile) {
98+
font-size: 14px;
99+
margin: 0 0.6rem;
100+
}
101+
}
102+
}
103+
}
104+
</style>

app/pages/index.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,17 @@ import {
1717
// eslint-disable-next-line @typescript-eslint/no-unused-vars
1818
useHead,
1919
useSeoMeta,
20+
defineAsyncComponent,
2021
} from "#imports";
2122
2223
defineRouteRules({ prerender: true });
2324
2425
const { t } = useI18n();
2526
27+
const SectionStaff = import.meta.vfFeatures.staff
28+
? defineAsyncComponent(() => import("./_components/SectionStaff.vue"))
29+
: null;
30+
2631
useSeoMeta({ title: "" });
2732
</script>
2833

@@ -39,6 +44,7 @@ useSeoMeta({ title: "" });
3944
<SectionAccess />
4045
<SectionMessage />
4146
<SectionContact />
47+
<SectionStaff v-if="SectionStaff" />
4248
</div>
4349

4450
<h2 class="sns-introduction-heading">

0 commit comments

Comments
 (0)