-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[WEB-393] feat: new emoji picker using
emoji-picker-react
(#3868)
* chore: emoji-picker-react package added * chore: emoji and emoji picker component added * chore: emoji picker custom style added * chore: migration of the emoji's * chore: migration changes * chore: project logo prop * chore: added logo props in the serializer * chore: removed unused keys * chore: implement emoji picker throughout the web app * style: emoji icon picker * chore: update project logo renderer in the space app * chore: migrations fixes --------- Co-authored-by: Anmol Singh Bhatia <[email protected]> Co-authored-by: NarayanBavisetti <[email protected]>
- Loading branch information
1 parent
b3d3c0f
commit e4f48d6
Showing
58 changed files
with
1,513 additions
and
2,462 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# 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.AlterField( | ||
model_name="issuelink", | ||
name="url", | ||
field=models.TextField(), | ||
), | ||
migrations.AddField( | ||
model_name="project", | ||
name="logo_props", | ||
field=models.JSONField(default=dict), | ||
), | ||
migrations.RunPython(update_project_logo_props), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
); | ||
}; |
Oops, something went wrong.