Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 37 additions & 197 deletions web/components/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import ThreeSixtyIcon from "@mui/icons-material/ThreeSixty";
import { Chip } from "@mui/material";
import { useEffect, useState } from "react";
import { useState } from "react";
import type { User, UserID } from "~/common/types";
import NonEditableCoursesTable from "./course/NonEditableCoursesTable";
import UserAvatar from "./human/avatar";
Expand All @@ -19,61 +19,33 @@ export function Card({ displayedUser, comparisonUserId, onFlip }: CardProps) {
if (onFlip) onFlip(!isDisplayingBack);
};

// biome-ignore lint: FIXME! 本来はuseEffectではなくスワイプのイベントで実装するべき
useEffect(() => {
const card = document.getElementById("card");

if (card) {
card.style.transition = "none";
setIsDisplayingBack(false);

requestAnimationFrame(() => {
if (card) {
card.style.transition = "transform 600ms";
}
});
}
}, [displayedUser]);

return (
// biome-ignore lint: this cannot just be fixed rn FIXME!
<div
style={{
perspective: "1000px",
width: "min(40dvh, 87.5vw)",
height: "70dvh",
position: "relative",
}}
className="perspective-[1000px] relative cursor-pointer"
style={{ width: "min(40dvh, 87.5vw)", height: "70dvh" }}
onClick={handleRotate}
onKeyDown={(event) => {
if (event.key === "Enter" || event.key === " ") handleRotate();
}}
>
<div
id="card"
style={{
position: "absolute",
width: "100%",
height: "100%",
transformStyle: "preserve-3d",
transition: "transform 600ms",
transform: isDisplayingBack ? "rotateY(180deg)" : "rotateY(0deg)",
}}
className="transform-style-preserve-3d absolute h-full w-full transition-transform duration-600"
>
<div
className="absolute h-full w-full"
style={{
position: "absolute",
width: "100%",
height: "100%",
backfaceVisibility: "hidden",
transform: isDisplayingBack ? "rotateY(180deg)" : "rotateY(0deg)",
}}
>
<CardFront displayedUser={displayedUser} />
</div>
<div
className="absolute h-full w-full"
style={{
position: "absolute",
width: "100%",
height: "100%",
backfaceVisibility: "hidden",
transform: "rotateY(180deg)",
transform: isDisplayingBack ? "rotateY(0deg)" : "rotateY(-180deg)",
}}
>
<CardBack
Expand All @@ -88,194 +60,62 @@ export function Card({ displayedUser, comparisonUserId, onFlip }: CardProps) {

const CardFront = ({ displayedUser }: CardProps) => {
return (
<div
style={{
display: "flex",
flexDirection: "column",
backgroundColor: "#F7FCFF",
border: "2px solid #3596C6",
padding: "20px 20px 10px 20px",
height: "100%",
gap: "2dvh",
overflow: "hidden",
justifyContent: "space-between",
}}
>
<div
style={{
display: "grid",
gridTemplateColumns: "1fr 1fr 1fr",
alignItems: "center",
height: "30%",
}}
>
<div className="flex h-full flex-col justify-between gap-5 overflow-hidden border-2 border-primary bg-secondary p-5">
<div className="grid h-[30%] grid-cols-3 items-center">
<UserAvatar
pictureUrl={displayedUser.pictureUrl}
width="10dvh"
height="10dvh"
/>
<div
style={{
display: "flex",
gridColumn: "2 / 4",
marginLeft: "1dvh",
justifyContent: "center",
}}
>
<span
style={{
fontSize: "3.4vh",
fontWeight: "bold",
margin: "0 auto",
}}
>
{displayedUser.name}
</span>
<div className="col-span-2 ml-2 flex justify-center">
<span className="font-bold text-4xl">{displayedUser.name}</span>
</div>
</div>
<div
style={{
display: "grid",
gridTemplateColumns: "1fr 5fr",
alignItems: "center",
gap: "1.5dvh",
}}
>
<Chip
label="学部"
size="small"
sx={{
gridColumn: "1 / 2",
}}
/>
<p
style={{
margin: 0,
fontSize: "3dvh",
}}
>
{displayedUser.faculty}
</p>
<div className="grid grid-cols-6 items-center gap-4">
<Chip label="学部" size="small" className="col-span-1" />
<p className="col-span-5 text-xl">{displayedUser.faculty}</p>
</div>
<div
style={{
display: "grid",
gridTemplateColumns: "1fr 5fr",
alignItems: "center",
gap: "1.5dvh",
}}
>
<Chip label="学科" size="small" />
<div className="grid grid-cols-6 items-center gap-4">
<Chip label="学科" size="small" className="col-span-1" />
<p
style={
displayedUser.department.length <= 7
? {
margin: 0,
fontSize: "3dvh",
overflow: "hidden",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
}
: {
margin: 0,
fontSize: "1.76dvh",
overflow: "hidden",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
}
}
className={`col-span-5 text-xl ${displayedUser.department.length > 7 ? "text-xs" : "text-2xl"}`}
>
{displayedUser.department}
</p>
</div>
<div
style={{
display: "grid",
gridTemplateColumns: "1fr 5fr",
alignItems: "center",
gap: "1.5dvh",
}}
>
<Chip label="性別" size="small" />
<p style={{ margin: 0, fontSize: "3dvh" }}>{displayedUser.gender}</p>
<div className="grid grid-cols-6 items-center gap-4">
<Chip label="性別" size="small" className="col-span-1" />
<p className="col-span-5 text-xl">{displayedUser.gender}</p>
</div>
<div
style={{
display: "grid",
gridTemplateColumns: "1fr 5fr",
alignItems: "center",
gap: "1.5dvh",
}}
>
<Chip label="学年" size="small" />
<p style={{ margin: 0, fontSize: "3dvh" }}> {displayedUser.grade}</p>
<div className="grid grid-cols-6 items-center gap-4">
<Chip label="学年" size="small" className="col-span-1" />
<p className="col-span-5 text-xl">{displayedUser.grade}</p>
</div>
<div
style={{
flex: 1,
display: "grid",
gridTemplateColumns: "1fr 5fr",
gap: "1.5dvh",
maxHeight: "32%", // WebKitLineClamp の フォールバックとして
}}
>
<Chip
label="自己紹介"
size="small"
sx={{
fontSize: "0.45rem",
}}
/>
<p
style={{
margin: 0,
fontSize: "1.76dvh",
overflow: "hidden",
display: "-webkit-box",
WebkitBoxOrient: "vertical",
WebkitLineClamp: 8,
lineClamp: 8,
textOverflow: "ellipsis",
}}
>
<div className="grid max-h-[32%] flex-1 grid-cols-6 gap-4">
<Chip label="自己紹介" size="small" className="col-span-1 text-sm" />
<p className="col-span-5 line-clamp-8 overflow-hidden text-sm">
{displayedUser.intro}
</p>
</div>
<div>
<ThreeSixtyIcon
style={{ fontSize: "3.08dvh", display: "block", margin: "auto" }}
/>
<div className="flex justify-center">
<ThreeSixtyIcon className="text-3xl" />
</div>
</div>
);
};

const CardBack = ({ displayedUser, comparisonUserId }: CardProps) => {
return (
<div
style={{
display: "flex",
flexDirection: "column",
backgroundColor: "#F7FCFF",
border: "2px solid #3596C6",
padding: "10px",
height: "100%",
overflow: "hidden",
}}
>
<div style={{ display: "flex", justifyContent: "center" }}>
<p style={{ fontSize: "1rem", fontWeight: "bold" }}>
{displayedUser?.name}
</p>
<div className="flex h-full flex-col overflow-hidden border-2 border-primary bg-secondary p-4">
<div className="flex justify-center">
<p className="font-bold text-lg">{displayedUser?.name}</p>
</div>
<NonEditableCoursesTable
userId={displayedUser.id}
comparisonUserId={comparisonUserId}
/>
<div>
<ThreeSixtyIcon
style={{ fontSize: "3.08dvh", display: "block", margin: "auto" }}
/>
<div className="mt-4 flex justify-center">
<ThreeSixtyIcon className="text-3xl" />
</div>
</div>
);
Expand Down
Loading