-
Notifications
You must be signed in to change notification settings - Fork 338
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
Add Custom Emojis Support #877
Conversation
I think a good solution would be to split the site settings page into different tabs. |
acef14f
to
7e08763
Compare
Question: is "Category" for emoji-mart? So these all wouldn't just go in a single "custom" category, but potentially many custom categories?
Sounds good to me.
Fairly sure you can define that custom library location in the package.json and it will download it to node_modules. If that doesn't work, you can reference the git repo, if the js file is hosted there. |
Yeah, Category is something for emoji-mart. You can add emojis to custom categories and it will group them. |
7aac252
to
ec86651
Compare
105e39e
to
390b44e
Compare
6a25461
to
a4212dd
Compare
Okay with the latest commit, the emoji picker will place a markdown image, with its 'title' attr set to the shortcode. When the markdown renderer encounters an image, it will check if it is a custom emoji, and if so it will add the 'icon-emoji' css class, which limits the size of the image. |
68708f0
to
e8f57bc
Compare
I'm just getting around to testing this now. There doesn't seem to be a save button for adding the custom emojis. |
Its the icon on each row next to the delete button. Its not a great icon, but couldn't find any better suiting ones. |
src/shared/utils.ts
Outdated
|
||
|
||
let custom_emojis: any[] = []; | ||
let custom_emojis_lookup: { [k: string]: CustomEmojiView } = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use a typescript Map<X, Y>
for this, and probably add it to the globals near the top. camelCase too.
src/shared/utils.ts
Outdated
@@ -678,6 +673,104 @@ export function setupTribute() { | |||
}); | |||
} | |||
|
|||
|
|||
|
|||
let custom_emojis: any[] = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type this strongly, and use camelCase for typescript vars. It should probably be moved to the top too, since its a global.
<button | ||
className={`nav-link btn ${this.state.currentTab == "emojis" && "active" | ||
}`} | ||
onClick={() => { this.handleSwitchTab("emojis"); }}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use linkEvent here. Check settings.tsx
for an example.
<li className="nav-item"> | ||
<button | ||
className={`nav-link btn ${this.state.currentTab == "site" && "active"}`} | ||
onClick={() => { this.handleSwitchTab("site"); }}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same, use linkEvent.
htmlFor={index.toString()} | ||
className="pointer text-muted small font-weight-bold" | ||
> | ||
{cv.image_url.length > 0 && <img style="max-width: 24px; max-height: 24px; display: inline-block;" src={cv.image_url} />} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use a style in main.css
disabled={cv.id > 0} | ||
value={cv.shortcode} | ||
onInput={(s: any) => | ||
this.handleEmojiShortCodeChange(s.target.value, index) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All these should use linkEvent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With linkEvent, I can't pass any parameters to the function. I can technically embed it in the html element, but that seems so much messier. I've already done same function calls in earlier PRs without linkEvent. From documentation, it just seems like its slightly faster?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To pass data to linkEvent, do:
onClick = {linkEvent(
{some_data_here},
this.handleBleh
)}
<br /> | ||
<button | ||
className="btn btn-sm btn-secondary mr-2" | ||
onClick={e => this.handleAddEmojiClick(e)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have a button to add a block, but no button to save the emojis to lemmy.
let data = wsJsonToRes<DeleteCustomEmojiResponse>(msg); | ||
if (data.success) { | ||
let custom_emojis = [...this.state!.custom_emojis.filter(x => x.id != data.id)]; | ||
this.setState({ custom_emojis }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should also be updating the global emoji list / maps.
That icon looks like an edit. Once you turn it from a table into a bootstrap form, it'll probably be better to name the button |
00cdbd8
to
000e1f6
Compare
Among many fixes today, i added pagination to the admin panel for emojis, to deal with performance issues with large size lists. |
4d0d280
to
0d64ebc
Compare
{this.admins()} | ||
{this.bannedUsers()} | ||
</div> | ||
<div > |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weird extra space, wonder how this is passing lint.
@@ -179,6 +209,11 @@ export class AdminSettings extends Component<any, AdminSettingsState> { | |||
); | |||
} | |||
|
|||
handleSwitchTab(i: AdminSettings, event: any) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the convention for tab switching from settings.tsx
, line 214 .
@@ -226,6 +228,7 @@ export class MarkdownTextArea extends Component< | |||
> | |||
<Icon icon="link" classes="icon-inline" /> | |||
</button> | |||
<EmojiPicker onEmojiClick={(e) => this.handleEmoji(this,e)}></EmojiPicker> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use linkEvent
page: number; | ||
} | ||
|
||
class CustomEmojiViewForm { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this a class and not an interface?
> | ||
<thead className="pointer"> | ||
<tr> | ||
<th style="width:70px;">{i18n.t("column_emoji")}</th> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, but at the very least remove the hard-coded widths ( those aren't going to be correct for any device but the one you coded them from), and use bootstrap table directives like in communities.tsx
. As I said though, tables are really terrible for skinny devices like phones, which is why we eventually need to get rid of that, and switch to using responsive design.
Bootstrap has responsive form examples, which is what this is, and we have a good amount of responsive forms in lemmy.
disabled={cv.id > 0} | ||
value={cv.shortcode} | ||
onInput={(s: any) => | ||
this.handleEmojiShortCodeChange(s.target.value, index) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To pass data to linkEvent, do:
onClick = {linkEvent(
{some_data_here},
this.handleBleh
)}
</tr> | ||
</thead> | ||
<tbody> | ||
{this.state.customEmojis.slice((this.state.page - 1) * this.itemsPerPage, ((this.state.page - 1) * this.itemsPerPage) + this.itemsPerPage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leave complicated front-end paging logic out of this, if we need to later, we can add it in the back end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding paging: All emojis are already loaded on frontend, no need to pull pages from server. We are paging on admin settings because showing all emojis at once (especially when you get to the thousands) causes page to slow to a crawl and become unusable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're really getting to the level of crashing the front end because there are too many emojis, then we really need to take them out of GetSite
into a paged emoji fetcher.
Front end hacks like this have to be replicated on all lemmy front ends, which means we're not structuring things correctly. I'm okay with merging this as is, but please add an issue to the Lemmy repo for breaking emojis into its own paged endpoint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would consider adding a hardcoded emoji limit in the backend then. If you hit the limit, you just need to remove an existing emoji before adding a new one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All users need all of the emojis available; when they open the emoji-picker, we need to know what to put in there all at once, not paged. Because of this, its kind of pointless to also have paged endpoints for emojis. I personally consider front-end paging pretty trivial; its mainly necessary once you get to the number of emojis that sites like hexbear have, which ends up with >2000 elements. Rendering all those at once is unfortunately a weakness of html and will cause page to get unresponsive.
Adding a hard coded limit would be unfortunate, as hexbear would be way over the limit of what is responsive on that page. Seems unnecessary, since the obvious way to work with it is just paginating on the front end. Alternate frontends can go without paginating, as long as they understand that it will get slower as more emojis are added.
this.setState({ page: page }); | ||
} | ||
|
||
handleEmojiClick = (e: any) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No closures, functions only please.
@dessalines Okay I fixed the comments. I updated the table to be more like communities. I do still have the last column with a set width, because the table doesn't really allow two elements in the same column without wrapping it, causing the row width the expand |
cca7d16
to
fc85823
Compare
c6205fe
to
96827a0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once the back-end gets merged, I'll test this again, and merge it if everything works correctly.
</tr> | ||
</thead> | ||
<tbody> | ||
{this.state.customEmojis.slice((this.state.page - 1) * this.itemsPerPage, ((this.state.page - 1) * this.itemsPerPage) + this.itemsPerPage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're really getting to the level of crashing the front end because there are too many emojis, then we really need to take them out of GetSite
into a paged emoji fetcher.
Front end hacks like this have to be replicated on all lemmy front ends, which means we're not structuring things correctly. I'm okay with merging this as is, but please add an issue to the Lemmy repo for breaking emojis into its own paged endpoint.
@dessalines Hey, any open requests for changes here? Or just need to test? |
Okay I deployed the new lemmy-js-client, and merged this fixing a few conflicts. |
This PR adds the custom emoji functionality from LemmyNet/lemmy#2419 (comment)
In the frontend, I've added the following:
Update markdown-textarea to handle emoji-picker
Update app startup to build emoji list from siteres
Update Tribute component to include custom emojis
Tabify Site Settings page
Add Custom Emoji admin tab for add/edit/delete custom emojis. Clicking on emoji in picker will scroll to entry in table.
Deficiencies:
Open Questions: