Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WEB-393] feat: new emoji picker using emoji-picker-react #3868

Merged
merged 22 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
582cd87
chore: emoji-picker-react package added
anmolsinghbhatia Dec 19, 2023
839ff36
chore: emoji and emoji picker component added
anmolsinghbhatia Dec 19, 2023
371b544
chore: emoji picker custom style added
anmolsinghbhatia Dec 19, 2023
46adf58
chore: migration of the emoji's
NarayanBavisetti Dec 28, 2023
6d759ab
chore: migration changes
NarayanBavisetti Dec 28, 2023
1a4412f
fix: merge conflicts resolved from develop
aaryan610 Feb 26, 2024
eb317e8
Merge branch 'develop' of https://github.com/makeplane/plane into dev…
aaryan610 Mar 1, 2024
8d92bc4
chore: project logo prop
NarayanBavisetti Mar 4, 2024
669d64b
Merge branch 'dev/emoji' of https://github.com/makeplane/plane into d…
aaryan610 Mar 4, 2024
3041e66
chore: added logo props in the serializer
NarayanBavisetti Mar 4, 2024
fd40334
Merge branch 'dev/emoji' of https://github.com/makeplane/plane into d…
aaryan610 Mar 4, 2024
07b2a20
chore: removed unused keys
NarayanBavisetti Mar 4, 2024
607a7b0
chore: implement emoji picker throughout the web app
aaryan610 Mar 4, 2024
633aba2
Merge branch 'dev/emoji' of https://github.com/makeplane/plane into d…
aaryan610 Mar 4, 2024
183d156
style: emoji icon picker
aaryan610 Mar 5, 2024
33c75f3
chore: update project logo renderer in the space app
aaryan610 Mar 5, 2024
50455cd
fix: merge conflicts resolved from develop
aaryan610 Mar 6, 2024
9e7b81e
Merge branch 'develop' of github.com:makeplane/plane into dev/emoji
NarayanBavisetti Mar 6, 2024
e20ce85
chore: migrations fixes
NarayanBavisetti Mar 6, 2024
0c61e59
Merge branch 'dev/emoji' of github.com:makeplane/plane into dev/emoji
NarayanBavisetti Mar 6, 2024
1538323
fix: merge conflicts resolved from develop
aaryan610 Mar 6, 2024
114f904
Merge branch 'dev/emoji' of https://github.com/makeplane/plane into d…
aaryan610 Mar 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions apiserver/plane/app/serializers/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@ class Meta:
"identifier",
"name",
"cover_image",
"icon_prop",
"emoji",
"logo_props",
"description",
]
read_only_fields = fields
Expand Down
4 changes: 0 additions & 4 deletions apiserver/plane/app/views/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -1303,10 +1303,6 @@ def get(self, request, slug, user_id):
)
.values(
"id",
"name",
"identifier",
"emoji",
"icon_prop",
"created_issues",
"assigned_issues",
"completed_issues",
Expand Down
49 changes: 49 additions & 0 deletions apiserver/plane/db/migrations/0061_project_logo_props.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Generated by Django 4.2.7 on 2024-03-03 16:25

from django.db import migrations, models


class Migration(migrations.Migration):

def update_project_logo_props(apps, schema_editor):
Project = apps.get_model("db", "Project")

bulk_update_project_logo = []
# Iterate through projects and update logo_props
for project in Project.objects.all():
project.logo_props["in_use"] = "emoji" if project.emoji else "icon"
project.logo_props["emoji"] = {
"value": project.emoji if project.emoji else "",
"url": "",
}
project.logo_props["icon"] = {
"name": (
project.icon_prop.get("name", "")
if project.icon_prop
else ""
),
"color": (
project.icon_prop.get("color", "")
if project.icon_prop
else ""
),
}
bulk_update_project_logo.append(project)

# Bulk update logo_props for all projects
Project.objects.bulk_update(
bulk_update_project_logo, ["logo_props"], batch_size=1000
)

dependencies = [
("db", "0060_cycle_progress_snapshot"),
]

operations = [
migrations.AddField(
model_name="project",
name="logo_props",
field=models.JSONField(default=dict),
),
migrations.RunPython(update_project_logo_props),
]
1 change: 1 addition & 0 deletions apiserver/plane/db/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ class Project(BaseModel):
close_in = models.IntegerField(
default=0, validators=[MinValueValidator(0), MaxValueValidator(12)]
)
logo_props = models.JSONField(default=dict)
default_state = models.ForeignKey(
"db.State",
on_delete=models.SET_NULL,
Expand Down
27 changes: 15 additions & 12 deletions packages/types/src/projects.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
import { EUserProjectRoles } from "constants/project";
import type {
IProjectViewProps,
IUser,
IUserLite,
IUserMemberLite,
IWorkspace,
IWorkspaceLite,
TStateGroups,
} from ".";

export type TProjectLogoProps = {
in_use: "emoji" | "icon";
emoji?: {
value?: string;
url?: string;
};
icon?: {
name?: string;
color?: string;
};
};

export interface IProject {
archive_in: number;
close_in: number;
Expand All @@ -21,24 +35,13 @@ export interface IProject {
default_assignee: IUser | string | null;
default_state: string | null;
description: string;
emoji: string | null;
emoji_and_icon:
| string
| {
name: string;
color: string;
}
| null;
estimate: string | null;
icon_prop: {
name: string;
color: string;
} | null;
id: string;
identifier: string;
is_deployed: boolean;
is_favorite: boolean;
is_member: boolean;
logo_props: TProjectLogoProps;
member_role: EUserProjectRoles | null;
members: IProjectMemberLite[];
name: string;
Expand Down
4 changes: 0 additions & 4 deletions packages/types/src/users.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,7 @@ export interface IUserProfileProjectSegregation {
assigned_issues: number;
completed_issues: number;
created_issues: number;
emoji: string | null;
icon_prop: null;
id: string;
identifier: string;
name: string;
pending_issues: number;
}[];
user_data: {
Expand Down
1 change: 1 addition & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@headlessui/react": "^1.7.17",
"@popperjs/core": "^2.11.8",
"clsx": "^2.0.0",
"emoji-picker-react": "^4.5.16",
"react-color": "^2.19.3",
"react-dom": "^18.2.0",
"react-popper": "^2.3.0",
Expand Down
169 changes: 169 additions & 0 deletions packages/ui/src/emoji/emoji-icon-picker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import React, { useState } from "react";
import { usePopper } from "react-popper";
import EmojiPicker, { EmojiClickData, Theme } from "emoji-picker-react";
import { Popover, Tab } from "@headlessui/react";
import { Placement } from "@popperjs/core";
// components
import { IconsList } from "./icons-list";
// helpers
import { cn } from "../../helpers";

export enum EmojiIconPickerTypes {
EMOJI = "emoji",
ICON = "icon",
}

type TChangeHandlerProps =
| {
type: EmojiIconPickerTypes.EMOJI;
value: EmojiClickData;
}
| {
type: EmojiIconPickerTypes.ICON;
value: {
name: string;
color: string;
};
};

export type TCustomEmojiPicker = {
buttonClassName?: string;
className?: string;
closeOnSelect?: boolean;
defaultIconColor?: string;
defaultOpen?: EmojiIconPickerTypes;
disabled?: boolean;
dropdownClassName?: string;
label: React.ReactNode;
onChange: (value: TChangeHandlerProps) => void;
placement?: Placement;
searchPlaceholder?: string;
theme?: Theme;
};

const TABS_LIST = [
{
key: EmojiIconPickerTypes.EMOJI,
title: "Emojis",
},
{
key: EmojiIconPickerTypes.ICON,
title: "Icons",
},
];

export const CustomEmojiIconPicker: React.FC<TCustomEmojiPicker> = (props) => {
const {
buttonClassName,
className,
closeOnSelect = true,
defaultIconColor = "#5f5f5f",
defaultOpen = EmojiIconPickerTypes.EMOJI,
disabled = false,
dropdownClassName,
label,
onChange,
placement = "bottom-start",
searchPlaceholder = "Search",
theme,
} = props;
// refs
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
// popper-js
const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement,
modifiers: [
{
name: "preventOverflow",
options: {
padding: 20,
},
},
],
});

return (
<Popover as="div" className={cn("relative", className)}>
{({ close }) => (
<>
<Popover.Button as={React.Fragment}>
<button
type="button"
ref={setReferenceElement}
className={cn("outline-none", buttonClassName)}
disabled={disabled}
>
{label}
</button>
</Popover.Button>
<Popover.Panel className="fixed z-10">
<div
ref={setPopperElement}
style={styles.popper}
{...attributes.popper}
className={cn(
"h-80 w-80 bg-custom-background-100 rounded-md border-[0.5px] border-custom-border-300 overflow-hidden",
dropdownClassName
)}
>
<Tab.Group
as="div"
className="h-full w-full flex flex-col overflow-hidden"
defaultIndex={TABS_LIST.findIndex((tab) => tab.key === defaultOpen)}
>
<Tab.List as="div" className="grid grid-cols-2 gap-1 p-2">
{TABS_LIST.map((tab) => (
<Tab
key={tab.key}
className={({ selected }) =>
cn("py-1 text-sm rounded border border-custom-border-200", {
"bg-custom-background-80": selected,
"hover:bg-custom-background-90 focus:bg-custom-background-90": !selected,
})
}
>
{tab.title}
</Tab>
))}
</Tab.List>
<Tab.Panels as="div" className="h-full w-full overflow-y-auto">
<Tab.Panel>
<EmojiPicker
onEmojiClick={(val) => {
onChange({
type: EmojiIconPickerTypes.EMOJI,
value: val,
});
if (closeOnSelect) close();
}}
height="20rem"
width="100%"
theme={theme}
searchPlaceholder={searchPlaceholder}
previewConfig={{
showPreview: false,
}}
/>
</Tab.Panel>
<Tab.Panel>
<IconsList
defaultColor={defaultIconColor}
onChange={(val) => {
onChange({
type: EmojiIconPickerTypes.ICON,
value: val,
});
if (closeOnSelect) close();
}}
/>
</Tab.Panel>
</Tab.Panels>
</Tab.Group>
</div>
</Popover.Panel>
</>
)}
</Popover>
);
};
Loading
Loading