[WEB-5305] refactor: migrate emoji and logo components to propel and remove duplication (#8038)

This commit is contained in:
Anmol Singh Bhatia 2025-11-06 17:33:06 +05:30 committed by GitHub
parent 4927ef8c71
commit 9b3bd11c03
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 62 additions and 858 deletions

View file

@ -1,7 +1,7 @@
import { ProjectIcon } from "@plane/propel/icons";
// plane package imports
import { Logo } from "@plane/propel/emoji-icon-picker";
import { ProjectIcon } from "@plane/propel/icons";
import { cn } from "@plane/utils";
import { Logo } from "@/components/common/logo";
// plane web hooks
import { useProject } from "@/hooks/store/use-project";

View file

@ -1,11 +1,10 @@
"use client";
import { observer } from "mobx-react";
import { ProjectIcon } from "@plane/propel/icons";
// plane package imports
import { Logo } from "@plane/propel/emoji-icon-picker";
import { ProjectIcon } from "@plane/propel/icons";
import { CustomSearchSelect } from "@plane/ui";
// components
import { Logo } from "@/components/common/logo";
// hooks
import { useProject } from "@/hooks/store/use-project";

View file

@ -5,13 +5,13 @@ import { useParams } from "next/navigation";
import useSWR from "swr";
import { UserRound } from "lucide-react";
import { useTranslation } from "@plane/i18n";
import { Logo } from "@plane/propel/emoji-icon-picker";
import { ProjectIcon } from "@plane/propel/icons";
// plane package imports
import type { AnalyticsTableDataMap, WorkItemInsightColumns } from "@plane/types";
// plane web components
import { Avatar } from "@plane/ui";
import { getFileURL } from "@plane/utils";
import { Logo } from "@/components/common/logo";
// hooks
import { useAnalytics } from "@/hooks/store/use-analytics";
import { useProject } from "@/hooks/store/use-project";

View file

@ -1,103 +0,0 @@
"use client";
import type { FC } from "react";
// Due to some weird issue with the import order, the import of useFontFaceObserver
// should be after the imported here rather than some below helper functions as it is in the original file
// eslint-disable-next-line import/order
import useFontFaceObserver from "use-font-face-observer";
// plane imports
import { getEmojiSize, LUCIDE_ICONS_LIST, stringToEmoji } from "@plane/propel/emoji-icon-picker";
import type { TLogoProps } from "@plane/types";
type Props = {
logo: TLogoProps;
size?: number;
type?: "lucide" | "material";
};
export const Logo: FC<Props> = (props) => {
const { logo, size = 16, type = "material" } = props;
// destructuring the logo object
const { in_use, emoji, icon } = logo;
// derived values
const value = in_use === "emoji" ? emoji?.value : icon?.name;
const color = icon?.color;
const lucideIcon = LUCIDE_ICONS_LIST.find((item) => item.name === value);
const isMaterialSymbolsFontLoaded = useFontFaceObserver([
{
family: `Material Symbols Rounded`,
style: `normal`,
weight: `normal`,
stretch: `condensed`,
},
]);
// if no value, return empty fragment
if (!value) return <></>;
if (!isMaterialSymbolsFontLoaded) {
return (
<span
style={{
height: size,
width: size,
}}
className="rounded animate-pulse bg-custom-background-80"
/>
);
}
// emoji
if (in_use === "emoji") {
return (
<span
className="flex items-center justify-center"
style={{
fontSize: `${getEmojiSize(size)}rem`,
lineHeight: `${getEmojiSize(size)}rem`,
height: size,
width: size,
}}
>
{stringToEmoji(emoji?.value || "")}
</span>
);
}
// icon
if (in_use === "icon") {
return (
<>
{type === "lucide" ? (
<>
{lucideIcon && (
<lucideIcon.element
style={{
color: color,
height: size,
width: size,
}}
/>
)}
</>
) : (
<span
className="material-symbols-rounded"
style={{
fontSize: size,
color: color,
scale: "115%",
}}
>
{value}
</span>
)}
</>
);
}
// if no value, return empty fragment
return <></>;
};

View file

@ -1,8 +1,8 @@
import type { FC } from "react";
import { Logo } from "@plane/propel/emoji-icon-picker";
import type { ISvgIcons } from "@plane/propel/icons";
import type { TLogoProps } from "@plane/types";
import { getFileURL, truncateText } from "@plane/utils";
import { Logo } from "@/components/common/logo";
type TSwitcherIconProps = {
logo_props?: TLogoProps;

View file

@ -4,12 +4,11 @@ import type { FC } from "react";
import React from "react";
import { observer } from "mobx-react";
import { ChevronRightIcon } from "@plane/propel/icons";
import { Logo } from "@plane/propel/emoji-icon-picker";
// icons
import { Row } from "@plane/ui";
// helpers
import { cn } from "@plane/utils";
// components
import { Logo } from "@/components/common/logo";
import { useProject } from "@/hooks/store/use-project";
type Props = {

View file

@ -6,11 +6,11 @@ import { Check, Search } from "lucide-react";
import { Combobox } from "@headlessui/react";
// plane imports
import { useTranslation } from "@plane/i18n";
import { Logo } from "@plane/propel/emoji-icon-picker";
import { ProjectIcon, ChevronDownIcon } from "@plane/propel/icons";
import { ComboDropDown } from "@plane/ui";
import { cn } from "@plane/utils";
// components
import { Logo } from "@/components/common/logo";
// hooks
import { useDropdown } from "@/hooks/use-dropdown";
// plane web imports

View file

@ -1,11 +1,10 @@
import { useRouter } from "next/navigation";
import { Logo } from "@plane/propel/emoji-icon-picker";
import { PageIcon } from "@plane/propel/icons";
// plane import
import type { TActivityEntityData, TPageEntityData } from "@plane/types";
import { Avatar } from "@plane/ui";
import { calculateTimeAgo, getFileURL, getPageName } from "@plane/utils";
// components
import { Logo } from "@/components/common/logo";
import { ListItem } from "@/components/core/list";
// hooks
import { useMember } from "@/hooks/store/use-member";

View file

@ -1,9 +1,9 @@
import { useRouter } from "next/navigation";
// plane types
import { Logo } from "@plane/propel/emoji-icon-picker";
import type { TActivityEntityData, TProjectEntityData } from "@plane/types";
import { calculateTimeAgo } from "@plane/utils";
// components
import { Logo } from "@/components/common/logo";
import { ListItem } from "@/components/core/list";
import { MemberDropdown } from "@/components/dropdowns/member/dropdown";
// helpers

View file

@ -1,7 +1,7 @@
import { observer } from "mobx-react";
import { CloseIcon } from "@plane/propel/icons";
// components
import { Logo } from "@/components/common/logo";
import { Logo } from "@plane/propel/emoji-icon-picker";
// hooks
import { useProject } from "@/hooks/store/use-project";

View file

@ -4,9 +4,9 @@ import React, { useMemo, useState } from "react";
import { sortBy } from "lodash-es";
import { observer } from "mobx-react";
// ui
import { Logo } from "@plane/propel/emoji-icon-picker";
import { Loader } from "@plane/ui";
// components
import { Logo } from "@/components/common/logo";
import { FilterHeader, FilterOption } from "@/components/issues/issue-layouts/filters";
// hooks
import { useProject } from "@/hooks/store/use-project";

View file

@ -6,6 +6,7 @@ import { clone, isNil, pull, uniq, concat } from "lodash-es";
import scrollIntoView from "smooth-scroll-into-view-if-needed";
// plane types
import { EIconSize, ISSUE_PRIORITIES, STATE_GROUPS } from "@plane/constants";
import { Logo } from "@plane/propel/emoji-icon-picker";
import type { ISvgIcons } from "@plane/propel/icons";
import { CycleGroupIcon, CycleIcon, ModuleIcon, PriorityIcon, StateGroupIcon } from "@plane/propel/icons";
import type {
@ -26,8 +27,6 @@ import { EIssuesStoreType } from "@plane/types";
// plane ui
import { Avatar } from "@plane/ui";
import { renderFormattedDate, getFileURL } from "@plane/utils";
// components
import { Logo } from "@/components/common/logo";
// helpers
// store
import { store } from "@/lib/store-context";

View file

@ -1,10 +1,8 @@
import { useState } from "react";
import { observer } from "mobx-react";
// plane imports
import { EmojiIconPicker, EmojiIconPickerTypes } from "@plane/ui";
import { EmojiPicker, EmojiIconPickerTypes, Logo } from "@plane/propel/emoji-icon-picker";
import { cn } from "@plane/utils";
// components
import { Logo } from "@/components/common/logo";
// store
import type { TPageInstance } from "@/store/pages/base-page";
@ -27,7 +25,7 @@ export const PageEditorHeaderLogoPicker: React.FC<Props> = observer((props) => {
"max-h-[56px] pointer-events-auto": isLogoSelected,
})}
>
<EmojiIconPicker
<EmojiPicker
isOpen={isLogoPickerOpen}
handleToggle={(val) => setIsLogoPickerOpen(val)}
className="flex items-center justify-center"

View file

@ -2,7 +2,7 @@ import { useState } from "react";
import { observer } from "mobx-react";
import { SmilePlus } from "lucide-react";
// plane imports
import { EmojiIconPicker, EmojiIconPickerTypes } from "@plane/ui";
import { EmojiPicker, EmojiIconPickerTypes } from "@plane/propel/emoji-icon-picker";
import { cn } from "@plane/utils";
// store
import type { TPageInstance } from "@/store/pages/base-page";
@ -32,7 +32,7 @@ export const PageEditorHeaderRoot: React.FC<Props> = observer((props) => {
"opacity-100": isTitleEmpty,
})}
>
<EmojiIconPicker
<EmojiPicker
isOpen={isLogoPickerOpen}
handleToggle={(val) => setIsLogoPickerOpen(val)}
className="flex items-center justify-center"

View file

@ -3,11 +3,11 @@
import type { FC } from "react";
import { useRef } from "react";
import { observer } from "mobx-react";
import { Logo } from "@plane/propel/emoji-icon-picker";
import { PageIcon } from "@plane/propel/icons";
// plane imports
import { getPageName } from "@plane/utils";
// components
import { Logo } from "@/components/common/logo";
import { ListItem } from "@/components/core/list";
import { BlockItemAction } from "@/components/pages/list/block-item-action";
// hooks

View file

@ -8,13 +8,13 @@ import { Globe2, Lock } from "lucide-react";
import { ETabIndices, EPageAccess } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { Button } from "@plane/propel/button";
import { EmojiPicker, EmojiIconPickerTypes, Logo } from "@plane/propel/emoji-icon-picker";
import { PageIcon } from "@plane/propel/icons";
import type { TPage } from "@plane/types";
import { EmojiIconPicker, EmojiIconPickerTypes, Input } from "@plane/ui";
import { convertHexEmojiToDecimal, getTabIndex } from "@plane/utils";
import { Input } from "@plane/ui";
import { getTabIndex } from "@plane/utils";
// components
import { AccessField } from "@/components/common/access-field";
import { Logo } from "@/components/common/logo";
// hooks
import { usePlatformOS } from "@/hooks/use-platform-os";
@ -65,7 +65,7 @@ export const PageForm: React.FC<Props> = (props) => {
<div className="space-y-5 p-5">
<h3 className="text-xl font-medium text-custom-text-200">Create page</h3>
<div className="flex items-start gap-2 h-9 w-full">
<EmojiIconPicker
<EmojiPicker
isOpen={isOpen}
handleToggle={(val: boolean) => setIsOpen(val)}
className="flex items-center justify-center flex-shrink0"
@ -86,8 +86,8 @@ export const PageForm: React.FC<Props> = (props) => {
if (val?.type === "emoji")
logoValue = {
value: convertHexEmojiToDecimal(val.value.unified),
url: val.value.imageUrl,
value: val.value,
url: undefined,
};
else if (val?.type === "icon") logoValue = val.value;

View file

@ -2,7 +2,7 @@
import React from "react";
// components
import { Logo } from "@/components/common/logo";
import { Logo } from "@plane/propel/emoji-icon-picker";
// plane imports
import type { TPartialProject } from "@/plane-web/types";
// local imports

View file

@ -13,15 +13,13 @@ import { Disclosure, Transition } from "@headlessui/react";
import { useOutsideClickDetector } from "@plane/hooks";
// types
import { useTranslation } from "@plane/i18n";
import { Logo } from "@plane/propel/emoji-icon-picker";
import { ChevronDownIcon } from "@plane/propel/icons";
import { Tooltip } from "@plane/propel/tooltip";
import type { IUserProfileProjectSegregation } from "@plane/types";
// plane ui
import { Loader } from "@plane/ui";
import { cn, renderFormattedDate, getFileURL } from "@plane/utils";
// components
import { Logo } from "@/components/common/logo";
// helpers
// hooks
import { useAppTheme } from "@/hooks/store/use-app-theme";
import { useProject } from "@/hooks/store/use-project";

View file

@ -9,6 +9,7 @@ import { ArchiveRestoreIcon, Check, ExternalLink, LinkIcon, Lock, Settings, Tras
import { EUserPermissions, EUserPermissionsLevel, IS_FAVORITE_MENU_OPEN } from "@plane/constants";
import { useLocalStorage } from "@plane/hooks";
import { Button } from "@plane/propel/button";
import { Logo } from "@plane/propel/emoji-icon-picker";
import { setPromiseToast, setToast, TOAST_TYPE } from "@plane/propel/toast";
import { Tooltip } from "@plane/propel/tooltip";
import type { IProject } from "@plane/types";
@ -16,7 +17,6 @@ import type { TContextMenuItem } from "@plane/ui";
import { Avatar, AvatarGroup, ContextMenu, FavoriteStar } from "@plane/ui";
import { copyUrlToClipboard, cn, getFileURL, renderFormattedDate } from "@plane/utils";
// components
import { Logo } from "@/components/common/logo";
// hooks
import { useMember } from "@/hooks/store/use-member";
import { useProject } from "@/hooks/store/use-project";

View file

@ -3,14 +3,13 @@ import { Controller, useFormContext } from "react-hook-form";
// plane imports
import { ETabIndices } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { EmojiPicker, EmojiIconPickerTypes } from "@plane/propel/emoji-icon-picker";
import { EmojiPicker, EmojiIconPickerTypes, Logo } from "@plane/propel/emoji-icon-picker";
import { CloseIcon } from "@plane/propel/icons";
// plane types
import type { IProject } from "@plane/types";
// plane ui
import { getFileURL, getTabIndex } from "@plane/utils";
// components
import { Logo } from "@/components/common/logo";
import { ImagePickerPopover } from "@/components/core/image-picker-popover";
// plane web imports
import { ProjectTemplateSelect } from "@/plane-web/components/projects/create/template-select";

View file

@ -8,14 +8,12 @@ import { NETWORK_CHOICES, PROJECT_TRACKER_ELEMENTS, PROJECT_TRACKER_EVENTS } fro
import { useTranslation } from "@plane/i18n";
// plane imports
import { Button } from "@plane/propel/button";
import { EmojiPicker } from "@plane/propel/emoji-icon-picker";
import { EmojiPicker, EmojiIconPickerTypes, Logo } from "@plane/propel/emoji-icon-picker";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { Tooltip } from "@plane/propel/tooltip";
import type { IProject, IWorkspace } from "@plane/types";
import { CustomSelect, Input, TextArea, EmojiIconPickerTypes } from "@plane/ui";
import { CustomSelect, Input, TextArea } from "@plane/ui";
import { renderFormattedDate, getFileURL } from "@plane/utils";
// components
import { Logo } from "@/components/common/logo";
import { ImagePickerPopover } from "@/components/core/image-picker-popover";
import { TimezoneSelect } from "@/components/global";
// helpers

View file

@ -7,6 +7,7 @@ import { Combobox } from "@headlessui/react";
// plane ui
import { useTranslation } from "@plane/i18n";
import { Button } from "@plane/propel/button";
import { Logo } from "@plane/propel/emoji-icon-picker";
import { CloseIcon } from "@plane/propel/icons";
import { Checkbox, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
import { cn } from "@plane/utils";
@ -14,7 +15,6 @@ import { cn } from "@plane/utils";
import darkProjectAsset from "@/app/assets/empty-state/search/project-dark.webp?url";
import lightProjectAsset from "@/app/assets/empty-state/search/project-light.webp?url";
// components
import { Logo } from "@/components/common/logo";
import { SimpleEmptyState } from "@/components/empty-state/simple-empty-state-root";
// hooks
import { useProject } from "@/hooks/store/use-project";

View file

@ -7,9 +7,9 @@ import Link from "next/link";
import { useTranslation } from "@plane/i18n";
// ui
import { Button, getButtonStyling } from "@plane/propel/button";
import { Logo } from "@plane/propel/emoji-icon-picker";
import { Row } from "@plane/ui";
// components
import { Logo } from "@/components/common/logo";
// hooks
import { useProject } from "@/hooks/store/use-project";
// plane web imports

View file

@ -2,9 +2,9 @@ import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// plane imports
import { PROJECT_SETTINGS_CATEGORIES, PROJECT_SETTINGS_CATEGORY } from "@plane/constants";
import { Logo } from "@plane/propel/emoji-icon-picker";
import { getUserRole } from "@plane/utils";
// components
import { Logo } from "@/components/common/logo";
// hooks
import { useProject } from "@/hooks/store/use-project";
// local imports

View file

@ -7,7 +7,7 @@ import { Controller, useForm } from "react-hook-form";
import { ETabIndices, ISSUE_DISPLAY_FILTERS_BY_PAGE } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { Button } from "@plane/propel/button";
import { EmojiPicker, EmojiIconPickerTypes } from "@plane/propel/emoji-icon-picker";
import { EmojiPicker, EmojiIconPickerTypes, Logo } from "@plane/propel/emoji-icon-picker";
import { ViewsIcon } from "@plane/propel/icons";
import type {
IIssueDisplayFilterOptions,
@ -20,7 +20,6 @@ import { EViewAccess, EIssuesStoreType } from "@plane/types";
import { Input, TextArea } from "@plane/ui";
import { getComputedDisplayFilters, getComputedDisplayProperties, getTabIndex } from "@plane/utils";
// components
import { Logo } from "@/components/common/logo";
import { DisplayFiltersSelection, FiltersDropdown } from "@/components/issues/issue-layouts/filters";
import { WorkItemFiltersRow } from "@/components/work-item-filters/filters-row";
// hooks

View file

@ -4,11 +4,11 @@ import type { FC } from "react";
import { useRef } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { Logo } from "@plane/propel/emoji-icon-picker";
import { ViewsIcon } from "@plane/propel/icons";
// types
import type { IProjectView } from "@plane/types";
// components
import { Logo } from "@/components/common/logo";
import { ListItem } from "@/components/core/list";
// hooks
import { usePlatformOS } from "@/hooks/use-platform-os";

View file

@ -1,10 +1,10 @@
"use client";
import { Logo } from "@plane/propel/emoji-icon-picker";
import { PageIcon } from "@plane/propel/icons";
// plane imports
import type { IFavorite, TLogoProps } from "@plane/types";
// components
import { Logo } from "@/components/common/logo";
// plane web constants
import { FAVORITE_ITEM_ICONS, FAVORITE_ITEM_LINKS } from "@/plane-web/constants/sidebar-favorites";

View file

@ -15,12 +15,12 @@ import { Disclosure, Transition } from "@headlessui/react";
import { EUserPermissions, EUserPermissionsLevel, MEMBER_TRACKER_ELEMENTS } from "@plane/constants";
import { useOutsideClickDetector } from "@plane/hooks";
import { useTranslation } from "@plane/i18n";
import { Logo } from "@plane/propel/emoji-icon-picker";
import { ArchiveIcon, ChevronRightIcon } from "@plane/propel/icons";
import { Tooltip } from "@plane/propel/tooltip";
import { CustomMenu, DropIndicator, DragHandle, ControlLink } from "@plane/ui";
import { cn } from "@plane/utils";
// components
import { Logo } from "@/components/common/logo";
import { LeaveProjectModal } from "@/components/project/leave-project-modal";
import { PublishProjectModal } from "@/components/project/publish-project/modal";
// hooks

View file

@ -2,9 +2,8 @@ import { set } from "lodash-es";
import { action, computed, makeObservable, observable, reaction, runInAction } from "mobx";
// plane imports
import { EPageAccess } from "@plane/constants";
import type { TChangeHandlerProps } from "@plane/propel/emoji-icon-picker";
import type { TDocumentPayload, TLogoProps, TNameDescriptionLoader, TPage } from "@plane/types";
import type { TChangeHandlerProps } from "@plane/ui";
import { convertHexEmojiToDecimal } from "@plane/utils";
// plane web store
import { ExtendedBasePage } from "@/plane-web/store/pages/extended-base-page";
import type { RootStore } from "@/plane-web/store/root.store";
@ -448,8 +447,8 @@ export class BasePage extends ExtendedBasePage implements TBasePage {
let logoValue = {};
if (value?.type === "emoji")
logoValue = {
value: convertHexEmojiToDecimal(value.value.unified),
url: value.value.imageUrl,
value: value.value,
url: undefined,
};
else if (value?.type === "icon") logoValue = value.value;