generic avatar component
This commit is contained in:
parent
1501e6dea4
commit
020cd4c5ac
@ -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;
|
17
src/components/dashboard/org/status-page/status-page.tsx
Normal file
17
src/components/dashboard/org/status-page/status-page.tsx
Normal file
@ -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;
|
84
src/components/generic-avatar.tsx
Normal file
84
src/components/generic-avatar.tsx
Normal file
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user