generic avatar component

This commit is contained in:
Braydon 2024-09-20 07:36:48 -04:00
parent 1501e6dea4
commit 020cd4c5ac
8 changed files with 187 additions and 112 deletions

@ -17,11 +17,12 @@ const OrganizationLayout = ({
}: Readonly<{
children: ReactNode;
}>): ReactElement => {
const selectedOrganization: Organization | undefined =
useOrganizationContext((state: OrganizationState) => state.selected);
const organization: Organization | undefined = useOrganizationContext(
(state: OrganizationState) => state.selected
);
return (
<div className="h-full">
{selectedOrganization ? children : <NoOrganizationSelected />}
{organization ? children : <NoOrganizationSelected />}
</div>
);
};

@ -1,9 +1,11 @@
import { ReactElement } from "react";
import DashboardHeader from "@/components/dashboard/dashboard-header";
import StatusPageList from "@/components/dashboard/org/status-page/status-page-list";
const StatusPagesPage = (): ReactElement => (
<main className="flex flex-col gap-3">
<main className="h-full flex flex-col gap-10">
<DashboardHeader title="Status Pages" />
<StatusPageList />
</main>
);
export default StatusPagesPage;

@ -25,7 +25,7 @@ const NotFoundPage = (): ReactElement => (
<div className="flex flex-col justify-center">
<div className="flex flex-col gap-0.5 pointer-events-none">
<h1 className="text-3xl font-bold">Wrong Door!</h1>
<p className="max-w-72 text-lg opacity-75">
<p className="max-w-64 text-lg opacity-75">
The page you were looking for could not be found.
</p>
</div>

@ -0,0 +1,40 @@
"use client";
import { ReactElement } from "react";
import { Button } from "@/components/ui/button";
import SimpleTooltip from "@/components/simple-tooltip";
import { Organization } from "@/app/types/org/organization";
import { useOrganizationContext } from "@/app/provider/organization-provider";
import { OrganizationState } from "@/app/store/organization-store";
import { StatusPage as StatusPageType } from "@/app/types/page/status-page";
import StatusPage from "@/components/dashboard/org/status-page/status-page";
/**
* A list of status pages for the
* currently selected {@link Organization}.
*
* @constructor
*/
const StatusPageList = (): ReactElement => {
const organization: Organization | undefined = useOrganizationContext(
(state: OrganizationState) => state.selected
);
return (
<div className="flex flex-col gap-5">
{/* Create */}
<SimpleTooltip content="Create a new status page">
<Button className="w-24" variant="outline" size="sm" disabled>
Create
</Button>
</SimpleTooltip>
{/* Status Pages */}
{organization?.statusPages.map(
(statusPage: StatusPageType, index: number) => (
<StatusPage key={index} statusPage={statusPage} />
)
)}
</div>
);
};
export default StatusPageList;

@ -0,0 +1,17 @@
import { ReactElement } from "react";
import { StatusPage as StatusPageType } from "@/app/types/page/status-page";
/**
* The status page for an organization.
*
* @param statusPage
* @constructor
*/
const StatusPage = ({
statusPage,
}: {
statusPage: StatusPageType;
}): ReactElement => (
<div className="p-3.5 w-72 border rounded-lg">sdfdssdfsfs</div>
);
export default StatusPage;

@ -0,0 +1,84 @@
import * as React from "react";
import { ReactElement } from "react";
import { cva } from "class-variance-authority";
import Image from "next/image";
import InitialsAvatar from "react-initials-avatar";
import { cn } from "@/lib/utils";
/**
* The variants of the avatar.
*/
const avatarVariants = cva("relative rounded-full", {
variants: {
size: {
sm: "w-6 h-6",
default: "w-11 h-11",
},
},
defaultVariants: {
size: "default",
},
});
/**
* The props for the avatar.
*/
export type GenericAvatarProps = {
/**
* The image URL of the
* avatar to display, if any.
*/
image?: string | undefined;
/**
* The alt text for the image.
*/
imageAlt?: string;
/**
* The backup text to extract initials
* from if the avatar image is unavailable.
*/
initialsText: string;
/**
* The size of the avatar.
*/
size?: "sm" | "default";
/**
* The optional class name to apply to the logo.
*/
className?: string;
};
/**
* An avatar for a user.
*
* @param props the avatar props
* @return the avatar jsx
*/
const GenericAvatar = ({
image,
imageAlt,
initialsText,
size,
className,
}: GenericAvatarProps): ReactElement => (
<div className={cn(avatarVariants({ size, className }))}>
{image ? (
<Image
className="rounded-full"
src={image}
alt={imageAlt ?? ""}
fill
/>
) : (
<InitialsAvatar
className="w-full h-full flex justify-center items-center bg-muted rounded-full"
name={initialsText}
/>
)}
</div>
);
export default GenericAvatar;

@ -1,25 +1,7 @@
import * as React from "react";
import { ReactElement } from "react";
import { cva } from "class-variance-authority";
import Image from "next/image";
import InitialsAvatar from "react-initials-avatar";
import { cn } from "@/lib/utils";
import { Organization } from "@/app/types/org/organization";
/**
* The variants of the logo.
*/
const logoVariants = cva("relative rounded-full", {
variants: {
size: {
sm: "w-5 h-5",
default: "w-10 h-10",
},
},
defaultVariants: {
size: "default",
},
});
import GenericAvatar from "@/components/generic-avatar";
/**
* The props for this component.
@ -29,45 +11,30 @@ type OrganizationLogoProps = {
* The organization to show the logo for.
*/
organization: Organization;
/**
* The size of the logo.
*/
size?: "sm" | "default";
/**
* The optional class name to apply to the logo.
*/
className?: string;
};
} & Omit<
React.ComponentProps<typeof GenericAvatar>,
"image" | "imageAlt" | "initialsText"
>;
/**
* A logo for an organization.
* The logo for an organization.
*
* @param organization the organization
* @param size the size
* @param className additional class names
* @return the organization jsx
* @param organization the org to show the logo for
* @param props additional props
* @return the logo jsx
*/
const OrganizationLogo = ({
organization,
size,
className,
...props
}: OrganizationLogoProps): ReactElement => (
<div className={cn(logoVariants({ size, className }))}>
{organization.logo ? (
<Image
className="rounded-full"
src={`${process.env.NEXT_PUBLIC_CDN_ENDPOINT}/organizations/${organization.logo}.webp`}
alt={`${organization.name}'s Logo`}
fill
/>
) : (
<InitialsAvatar
className="-translate-y-0.5 w-[130%] h-[130%] flex justify-center items-center bg-muted rounded-full"
name={organization.name}
/>
)}
</div>
<GenericAvatar
image={
organization.logo &&
`${process.env.NEXT_PUBLIC_CDN_ENDPOINT}/organizations/${organization.logo}.webp`
}
imageAlt={`${organization.name}'s Logo`}
initialsText={organization.name}
{...props}
/>
);
export default OrganizationLogo;

@ -1,73 +1,37 @@
import * as React from "react";
import { ReactElement } from "react";
import { cva } from "class-variance-authority";
import Image from "next/image";
import InitialsAvatar from "react-initials-avatar";
import { cn } from "@/lib/utils";
import { User } from "@/app/types/user/user";
import GenericAvatar from "@/components/generic-avatar";
/**
* The variants of the avatar.
*/
const avatarVariants = cva("relative rounded-full", {
variants: {
size: {
sm: "w-6 h-6",
default: "w-11 h-11",
},
},
defaultVariants: {
size: "default",
},
});
/**
* The props for this component.
* The props for the avatar.
*/
type UserAvatarProps = {
/**
* The user to show the avatar for.
*/
user: User;
/**
* The size of the avatar.
*/
size?: "sm" | "default";
/**
* The optional class name to apply to the logo.
*/
className?: string;
};
} & Omit<
React.ComponentProps<typeof GenericAvatar>,
"image" | "imageAlt" | "initialsText"
>;
/**
* An avatar for a user.
* The avatar for a user.
*
* @param user the user
* @param size the size
* @param className additional class names
* @param user the user to show the avatar for
* @param props additional props
* @return the avatar jsx
*/
const UserAvatar = ({
user,
size,
className,
}: UserAvatarProps): ReactElement => (
<div className={cn(avatarVariants({ size, className }))}>
{user.avatar ? (
<Image
className="rounded-full"
src={`${process.env.NEXT_PUBLIC_CDN_ENDPOINT}/avatars/${user.avatar}.webp`}
alt={`${user.username}'s Avatar`}
fill
/>
) : (
<InitialsAvatar
className="w-full h-full flex justify-center items-center bg-muted rounded-full"
name={user.username}
/>
)}
</div>
const UserAvatar = ({ user, ...props }: UserAvatarProps): ReactElement => (
<GenericAvatar
image={
user.avatar &&
`${process.env.NEXT_PUBLIC_CDN_ENDPOINT}/avatars/${user.avatar}.webp`
}
imageAlt={`${user.username}'s Avatar`}
initialsText={user.username}
{...props}
/>
);
export default UserAvatar;