feat: implement space and workspace icons (#1558)

* feat: implement space and workspace icons
- Create reusable AvatarUploader component supporting avatars, space icons, and workspace icons
- Add Sharp package for server-side image resizing and optimization
- Create reusable AvatarUploader component supporting avatars, space icons, and workspace icons
- Support removing icons

* add workspace logo support
- add upload loader
- add white background to transparent image
- other fixes and enhancements

* dark mode

* fixes

* cleanup
This commit is contained in:
Philip Okugbe
2025-09-15 21:11:37 +01:00
committed by GitHub
parent 61d1cf88a7
commit 1280f96f37
41 changed files with 1043 additions and 213 deletions
@@ -1,17 +1,25 @@
import classes from './switch-space.module.css';
import { useNavigate } from 'react-router-dom';
import { SpaceSelect } from './space-select';
import { getSpaceUrl } from '@/lib/config';
import { Avatar, Button, Popover, Text } from '@mantine/core';
import { IconChevronDown } from '@tabler/icons-react';
import { useDisclosure } from '@mantine/hooks';
import classes from "./switch-space.module.css";
import { useNavigate } from "react-router-dom";
import { SpaceSelect } from "./space-select";
import { getSpaceUrl } from "@/lib/config";
import { Button, Popover, Text } from "@mantine/core";
import { IconChevronDown } from "@tabler/icons-react";
import { useDisclosure } from "@mantine/hooks";
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
import { AvatarIconType } from "@/features/attachments/types/attachment.types.ts";
import React from "react";
interface SwitchSpaceProps {
spaceName: string;
spaceSlug: string;
spaceIcon?: string;
}
export function SwitchSpace({ spaceName, spaceSlug }: SwitchSpaceProps) {
export function SwitchSpace({
spaceName,
spaceSlug,
spaceIcon,
}: SwitchSpaceProps) {
const navigate = useNavigate();
const [opened, { close, open, toggle }] = useDisclosure(false);
@@ -40,11 +48,13 @@ export function SwitchSpace({ spaceName, spaceSlug }: SwitchSpaceProps) {
color="gray"
onClick={open}
>
<Avatar
size={20}
<CustomAvatar
name={spaceName}
avatarUrl={spaceIcon}
type={AvatarIconType.SPACE_ICON}
color="initials"
variant="filled"
name={spaceName}
size={20}
/>
<Text className={classes.spaceName} size="md" fw={500} lineClamp={1}>
{spaceName}
@@ -55,7 +65,7 @@ export function SwitchSpace({ spaceName, spaceSlug }: SwitchSpaceProps) {
<SpaceSelect
label={spaceName}
value={spaceSlug}
onChange={space => handleSelect(space.slug)}
onChange={(space) => handleSelect(space.slug)}
width={300}
opened={true}
/>