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)}
|
<HeartFill className="inline" /> {linkPronoun(entry)}
|
||||||
</p>
|
</p>
|
||||||
))}
|
))}
|
||||||
{field.okay?.length !== 0 && (
|
{field.okay && field.okay.length !== 0 && (
|
||||||
<p>
|
<p>
|
||||||
<HandThumbsUp className="inline" /> {field.okay!.join(", ")}
|
<HandThumbsUp className="inline" /> {field.okay!.join(", ")}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{field.jokingly?.length !== 0 && (
|
{field.jokingly && field.jokingly.length !== 0 && (
|
||||||
<p>
|
<p>
|
||||||
<EmojiLaughing className="inline" /> {field.jokingly!.join(", ")}
|
<EmojiLaughing className="inline" /> {field.jokingly!.join(", ")}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{field.friends_only?.length !== 0 && (
|
{field.friends_only && field.friends_only.length !== 0 && (
|
||||||
<p>
|
<p>
|
||||||
<People className="inline" /> {field.friends_only!.join(", ")}
|
<People className="inline" /> {field.friends_only!.join(", ")}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{field.avoid?.length !== 0 && (
|
{field.avoid && field.avoid.length !== 0 && (
|
||||||
<p className="text-slate-600 dark:text-slate-400">
|
<p className="text-slate-600 dark:text-slate-400">
|
||||||
<HandThumbsDown className="inline" /> {field.avoid!.join(", ")}
|
<HandThumbsDown className="inline" /> {field.avoid!.join(", ")}
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
export interface MeUser extends User {
|
export interface MeUser extends User {
|
||||||
avatar_source: string | null;
|
|
||||||
discord: string | null;
|
discord: string | null;
|
||||||
discord_username: string | null;
|
discord_username: string | null;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +8,7 @@ export interface User {
|
||||||
username: string;
|
username: string;
|
||||||
display_name: string | null;
|
display_name: string | null;
|
||||||
bio: string | null;
|
bio: string | null;
|
||||||
avatar_url: string | null;
|
avatar_urls: string[] | null;
|
||||||
links: string[] | null;
|
links: string[] | null;
|
||||||
members: PartialMember[];
|
members: PartialMember[];
|
||||||
fields: Field[];
|
fields: Field[];
|
||||||
|
@ -21,6 +20,17 @@ export interface PartialMember {
|
||||||
avatar_url: string | null;
|
avatar_url: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Name {
|
||||||
|
name: string;
|
||||||
|
status: WordStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Pronoun {
|
||||||
|
display_text?: string;
|
||||||
|
pronouns: string;
|
||||||
|
status: WordStatus;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Field {
|
export interface Field {
|
||||||
name: string;
|
name: string;
|
||||||
favourite: string[] | null;
|
favourite: string[] | null;
|
||||||
|
@ -36,6 +46,14 @@ export interface APIError {
|
||||||
details?: string;
|
details?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum WordStatus {
|
||||||
|
Favourite = 1,
|
||||||
|
Okay = 2,
|
||||||
|
Jokingly = 3,
|
||||||
|
FriendsOnly = 4,
|
||||||
|
Avoid = 5,
|
||||||
|
}
|
||||||
|
|
||||||
export enum ErrorCode {
|
export enum ErrorCode {
|
||||||
BadRequest = 400,
|
BadRequest = 400,
|
||||||
Forbidden = 403,
|
Forbidden = 403,
|
||||||
|
|
|
@ -9,6 +9,7 @@ import Image from "next/image";
|
||||||
import { userState } from "../../../lib/state";
|
import { userState } from "../../../lib/state";
|
||||||
import { useRecoilValue } from "recoil";
|
import { useRecoilValue } from "recoil";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import FallbackImage from "../../../components/FallbackImage";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
|
@ -39,13 +40,18 @@ export default function Index({ user }: Props) {
|
||||||
)}
|
)}
|
||||||
<div className="container mx-auto">
|
<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">
|
<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 && (
|
{user.avatar_urls && user.avatar_urls.length !== 0 && (
|
||||||
// eslint-disable-next-line @next/next/no-img-element
|
<FallbackImage
|
||||||
<img
|
|
||||||
className="max-w-xs rounded-full"
|
className="max-w-xs rounded-full"
|
||||||
src={user.avatar_url}
|
urls={user.avatar_urls}
|
||||||
alt={`@${user.username}'s avatar`}
|
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">
|
<div className="flex flex-col">
|
||||||
{user.display_name && (
|
{user.display_name && (
|
||||||
|
|
Loading…
Reference in a new issue