feat(frontend): support multiple avatar urls
This commit is contained in:
parent
85a061ebc5
commit
f2a298da75
4 changed files with 65 additions and 10 deletions
31
frontend/components/FallbackImage.tsx
Normal file
31
frontend/components/FallbackImage.tsx
Normal file
|
@ -0,0 +1,31 @@
|
|||
import { HTMLAttributes } from "react";
|
||||
|
||||
export interface Props extends HTMLAttributes<Props> {
|
||||
urls: string[];
|
||||
alt: string;
|
||||
}
|
||||
|
||||
export default function FallbackImage({ urls, alt, className }: Props) {
|
||||
const fallbackUrl = urls.pop()!;
|
||||
urls.push(fallbackUrl);
|
||||
|
||||
return (
|
||||
<picture className={className}>
|
||||
{urls.length !== 0 &&
|
||||
urls.map((url, key) => {
|
||||
let contentType: string;
|
||||
if (url.endsWith(".webp")) {
|
||||
contentType = "image/webp";
|
||||
} else if (url.endsWith(".jpg") || url.endsWith(".jpeg")) {
|
||||
contentType = "image/jpeg";
|
||||
} else if (url.endsWith(".png")) {
|
||||
contentType = "image/png";
|
||||
} else {
|
||||
contentType = "application/octet-stream";
|
||||
}
|
||||
return <source key={key} srcSet={url} type={contentType} />;
|
||||
})}
|
||||
<img src={fallbackUrl} alt={alt} className={className} />
|
||||
</picture>
|
||||
);
|
||||
}
|
|
@ -39,22 +39,22 @@ export default function FieldCard({
|
|||
<HeartFill className="inline" /> {linkPronoun(entry)}
|
||||
</p>
|
||||
))}
|
||||
{field.okay?.length !== 0 && (
|
||||
{field.okay && field.okay.length !== 0 && (
|
||||
<p>
|
||||
<HandThumbsUp className="inline" /> {field.okay!.join(", ")}
|
||||
</p>
|
||||
)}
|
||||
{field.jokingly?.length !== 0 && (
|
||||
{field.jokingly && field.jokingly.length !== 0 && (
|
||||
<p>
|
||||
<EmojiLaughing className="inline" /> {field.jokingly!.join(", ")}
|
||||
</p>
|
||||
)}
|
||||
{field.friends_only?.length !== 0 && (
|
||||
{field.friends_only && field.friends_only.length !== 0 && (
|
||||
<p>
|
||||
<People className="inline" /> {field.friends_only!.join(", ")}
|
||||
</p>
|
||||
)}
|
||||
{field.avoid?.length !== 0 && (
|
||||
{field.avoid && field.avoid.length !== 0 && (
|
||||
<p className="text-slate-600 dark:text-slate-400">
|
||||
<HandThumbsDown className="inline" /> {field.avoid!.join(", ")}
|
||||
</p>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
export interface MeUser extends User {
|
||||
avatar_source: string | null;
|
||||
discord: string | null;
|
||||
discord_username: string | null;
|
||||
}
|
||||
|
@ -9,7 +8,7 @@ export interface User {
|
|||
username: string;
|
||||
display_name: string | null;
|
||||
bio: string | null;
|
||||
avatar_url: string | null;
|
||||
avatar_urls: string[] | null;
|
||||
links: string[] | null;
|
||||
members: PartialMember[];
|
||||
fields: Field[];
|
||||
|
@ -21,6 +20,17 @@ export interface PartialMember {
|
|||
avatar_url: string | null;
|
||||
}
|
||||
|
||||
export interface Name {
|
||||
name: string;
|
||||
status: WordStatus;
|
||||
}
|
||||
|
||||
export interface Pronoun {
|
||||
display_text?: string;
|
||||
pronouns: string;
|
||||
status: WordStatus;
|
||||
}
|
||||
|
||||
export interface Field {
|
||||
name: string;
|
||||
favourite: string[] | null;
|
||||
|
@ -36,6 +46,14 @@ export interface APIError {
|
|||
details?: string;
|
||||
}
|
||||
|
||||
export enum WordStatus {
|
||||
Favourite = 1,
|
||||
Okay = 2,
|
||||
Jokingly = 3,
|
||||
FriendsOnly = 4,
|
||||
Avoid = 5,
|
||||
}
|
||||
|
||||
export enum ErrorCode {
|
||||
BadRequest = 400,
|
||||
Forbidden = 403,
|
||||
|
|
|
@ -9,6 +9,7 @@ import Image from "next/image";
|
|||
import { userState } from "../../../lib/state";
|
||||
import { useRecoilValue } from "recoil";
|
||||
import Link from "next/link";
|
||||
import FallbackImage from "../../../components/FallbackImage";
|
||||
|
||||
interface Props {
|
||||
user: User;
|
||||
|
@ -39,13 +40,18 @@ export default function Index({ user }: Props) {
|
|||
)}
|
||||
<div className="container mx-auto">
|
||||
<div className="flex flex-col m-2 p-2 lg:flex-row justify-center lg:justify-start items-center space-y-4 lg:space-y-0 lg:space-x-16 lg:items-start border-b border-slate-200 dark:border-slate-700">
|
||||
{user.avatar_url && (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
{user.avatar_urls && user.avatar_urls.length !== 0 && (
|
||||
<FallbackImage
|
||||
className="max-w-xs rounded-full"
|
||||
src={user.avatar_url}
|
||||
urls={user.avatar_urls}
|
||||
alt={`@${user.username}'s avatar`}
|
||||
/>
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
// <img
|
||||
// className="max-w-xs rounded-full"
|
||||
// src={user.avatar_url}
|
||||
// alt={`@${user.username}'s avatar`}
|
||||
// />
|
||||
)}
|
||||
<div className="flex flex-col">
|
||||
{user.display_name && (
|
||||
|
|
Loading…
Reference in a new issue