From 1f15ea5aa86a8bacfc965ea8e56fa11f5067c1a9 Mon Sep 17 00:00:00 2001 From: Anon Date: Sun, 27 Nov 2022 12:02:32 -0600 Subject: [PATCH] Add Custom Emoji Support --- lemmy-translations | 2 +- package.json | 3 + src/assets/css/main.css | 58 ++- src/shared/components/common/emoji-mart.tsx | 33 ++ src/shared/components/common/emoji-picker.tsx | 62 +++ .../components/common/markdown-textarea.tsx | 19 + src/shared/components/home/admin-settings.tsx | 68 ++- src/shared/components/home/emojis-form.tsx | 445 ++++++++++++++++++ src/shared/components/home/home.tsx | 2 +- src/shared/utils.ts | 194 ++++++-- yarn.lock | 43 +- 11 files changed, 877 insertions(+), 52 deletions(-) create mode 100644 src/shared/components/common/emoji-mart.tsx create mode 100644 src/shared/components/common/emoji-picker.tsx create mode 100644 src/shared/components/home/emojis-form.tsx diff --git a/lemmy-translations b/lemmy-translations index 7379716..819531a 160000 --- a/lemmy-translations +++ b/lemmy-translations @@ -1 +1 @@ -Subproject commit 7379716231b9f7e67f710751c839398b7ab5d65e +Subproject commit 819531ae64c6cba12cb406eb98333fd52988bf3e diff --git a/package.json b/package.json index 839a3d8..87f23d0 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@babel/preset-env": "7.20.2", "@babel/preset-typescript": "^7.21.0", "@babel/runtime": "^7.21.0", + "@emoji-mart/data": "^1.1.0", "autosize": "^6.0.1", "babel-loader": "^9.1.2", "babel-plugin-inferno": "^6.6.0", @@ -32,6 +33,7 @@ "clean-webpack-plugin": "^4.0.0", "copy-webpack-plugin": "^11.0.0", "css-loader": "^6.7.3", + "emoji-mart": "^5.4.0", "emoji-short-name": "^2.0.0", "express": "~4.18.2", "html-to-text": "^9.0.4", @@ -48,6 +50,7 @@ "lemmy-js-client": "0.17.2-rc.1", "markdown-it": "^13.0.1", "markdown-it-container": "^3.0.0", + "markdown-it-emoji": "^2.0.2", "markdown-it-footnote": "^3.0.3", "markdown-it-html5-embed": "^1.0.0", "markdown-it-sub": "^1.0.0", diff --git a/src/assets/css/main.css b/src/assets/css/main.css index 766c9db..e796b7f 100644 --- a/src/assets/css/main.css +++ b/src/assets/css/main.css @@ -62,15 +62,19 @@ .md-div h1 { font-size: 2rem; } + .md-div h2 { font-size: 1.8rem; } + .md-div h3 { font-size: 1.6rem; } + .md-div h4 { font-size: 1.4rem; } + .md-div h5 { font-size: 1.2rem; } @@ -95,7 +99,7 @@ border-bottom: 2px solid var(--dark); } -.md-div table tbody + tbody { +.md-div table tbody+tbody { border-top: 2px solid var(--dark); } @@ -129,10 +133,52 @@ user-select: none; } +.icon-emoji { + width: 4em; + height: auto; + max-height: inherit; +} + +.icon-emoji-admin { + max-width: 24px; + max-height: 24px; + display: inline-block; +} + .icon-inline { margin-bottom: 2px; } +.emoji-picker-container { + position: absolute; + top: 30px; + z-index: 1000; + transform: translateX(-50%); +} + +@media only screen and (max-width: 992px) { + .emoji-picker-container { + width: 100vw; + transform: translateX(0%); + position: fixed; + left: 0; + } + + .emoji-picker-container>section { + width: 100% !important; + } +} + +.click-away-container { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, .3); + z-index: 999; +} + .spinner-large { display: grid; display: block; @@ -149,6 +195,7 @@ 0% { transform: rotate(0deg); } + 100% { transform: rotate(359deg); } @@ -340,19 +387,24 @@ br.big { list-style: none; background: var(--light); } + .tribute-container li { padding: 5px 5px; cursor: pointer; } + .tribute-container li.highlight { background: var(--primary); } + .tribute-container li span { font-weight: bold; } + .tribute-container li.no-match { cursor: default; } + .tribute-container .menu-highlighted { font-weight: bold; } @@ -376,7 +428,6 @@ br.big { -webkit-line-clamp: 3; -webkit-box-orient: vertical; } - .lang-select-action { width: 100px; } @@ -384,3 +435,6 @@ br.big { .lang-select-action:focus { width: auto; } +em-emoji-picker{ + width:100%; +} diff --git a/src/shared/components/common/emoji-mart.tsx b/src/shared/components/common/emoji-mart.tsx new file mode 100644 index 0000000..39b09bc --- /dev/null +++ b/src/shared/components/common/emoji-mart.tsx @@ -0,0 +1,33 @@ +import { Component } from "inferno"; +import { getEmojiMart } from "../../utils"; + + +interface EmojiMartProps { + onEmojiClick?(val: any): any; + pickerOptions: any; +} + +export class EmojiMart extends Component< + EmojiMartProps +> { + constructor(props: any, context: any) { + super(props, context); + this.handleEmojiClick = this.handleEmojiClick.bind(this); + } + componentDidMount() { + let div: any = document.getElementById("emoji-picker"); + if (div) { + div.appendChild(getEmojiMart(this.handleEmojiClick, this.props.pickerOptions)); + } + } + + render() { + return ( +
+ ); + } + + handleEmojiClick(e: any) { + this.props.onEmojiClick?.(e); + } +} diff --git a/src/shared/components/common/emoji-picker.tsx b/src/shared/components/common/emoji-picker.tsx new file mode 100644 index 0000000..cb46651 --- /dev/null +++ b/src/shared/components/common/emoji-picker.tsx @@ -0,0 +1,62 @@ +import { Component, linkEvent } from "inferno"; +import { i18n } from "../../i18next"; +import { EmojiMart } from "./emoji-mart"; +import { Icon } from "./icon"; + +interface EmojiPickerProps { + onEmojiClick?(val: any): any; +} + +interface EmojiPickerState { + showPicker: boolean, +} + +export class EmojiPicker extends Component< + EmojiPickerProps, + EmojiPickerState +> { + private emptyState: EmojiPickerState = { + showPicker: false, + }; + state: EmojiPickerState; + constructor(props: any, context: any) { + super(props, context); + this.state = this.emptyState; + this.handleEmojiClick = this.handleEmojiClick.bind(this); + } + render() { + return ( + + + + {this.state.showPicker && ( + <> +
+ +
+
+ + )} + + ); + } + + togglePicker(i: EmojiPicker, e: any) { + e.preventDefault(); + i.setState({ showPicker: !i.state.showPicker }); + } + + handleEmojiClick(e: any) { + this.props.onEmojiClick?.(e); + } +} \ No newline at end of file diff --git a/src/shared/components/common/markdown-textarea.tsx b/src/shared/components/common/markdown-textarea.tsx index 48b9042..07a966c 100644 --- a/src/shared/components/common/markdown-textarea.tsx +++ b/src/shared/components/common/markdown-textarea.tsx @@ -6,6 +6,7 @@ import { pictrsUri } from "../../env"; import { i18n } from "../../i18next"; import { UserService } from "../../services"; import { + customEmojisLookup, isBrowser, markdownFieldCharacterLimit, markdownHelpUrl, @@ -17,6 +18,7 @@ import { setupTribute, toast, } from "../../utils"; +import { EmojiPicker } from "./emoji-picker"; import { Icon, Spinner } from "./icon"; import { LanguageSelect } from "./language-select"; @@ -226,6 +228,7 @@ export class MarkdownTextArea extends Component< > + this.handleEmoji(this,e)}>