| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 	GoToSocial | 
					
						
							| 
									
										
										
										
											2023-03-12 18:49:06 +01:00
										 |  |  | 	Copyright (C) GoToSocial Authors admin@gotosocial.org | 
					
						
							|  |  |  | 	SPDX-License-Identifier: AGPL-3.0-or-later | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 	This program is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | 	it under the terms of the GNU Affero General Public License as published by | 
					
						
							|  |  |  | 	the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | 	(at your option) any later version. | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 	This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | 	but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | 	GNU Affero General Public License for more details. | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 	You should have received a copy of the GNU Affero General Public License | 
					
						
							|  |  |  | 	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const React = require("react"); | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | const { Link } = require("wouter"); | 
					
						
							| 
									
										
										
										
											2023-01-27 09:09:26 +01:00
										 |  |  | const syncpipe = require("syncpipe"); | 
					
						
							|  |  |  | const { matchSorter } = require("match-sorter"); | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | const NewEmojiForm = require("./new-emoji"); | 
					
						
							| 
									
										
										
										
											2023-01-27 09:09:26 +01:00
										 |  |  | const { useTextInput } = require("../../../lib/form"); | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | const { useEmojiByCategory } = require("../category-select"); | 
					
						
							| 
									
										
										
										
											2023-03-29 12:18:45 +02:00
										 |  |  | const { useBaseUrl } = require("../../../lib/navigation/util"); | 
					
						
							| 
									
										
										
										
											2023-01-27 09:09:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | const Loading = require("../../../components/loading"); | 
					
						
							| 
									
										
										
										
											2023-01-25 09:47:55 +01:00
										 |  |  | const { Error } = require("../../../components/error"); | 
					
						
							| 
									
										
										
										
											2023-01-27 09:09:26 +01:00
										 |  |  | const { TextInput } = require("../../../components/form/inputs"); | 
					
						
							| 
									
										
										
										
											2023-10-17 12:46:06 +02:00
										 |  |  | const { useListEmojiQuery } = require("../../../lib/query/admin/custom-emoji"); | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-29 12:18:45 +02:00
										 |  |  | module.exports = function EmojiOverview({ }) { | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 	const { | 
					
						
							| 
									
										
										
										
											2022-11-16 17:05:49 +01:00
										 |  |  | 		data: emoji = [], | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 		isLoading, | 
					
						
							| 
									
										
										
										
											2023-01-25 09:47:55 +01:00
										 |  |  | 		isError, | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 		error | 
					
						
							| 
									
										
										
										
											2023-10-17 12:46:06 +02:00
										 |  |  | 	} = useListEmojiQuery({ filter: "domain:local" }); | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-25 09:47:55 +01:00
										 |  |  | 	let content = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (isLoading) { | 
					
						
							|  |  |  | 		content = <Loading />; | 
					
						
							|  |  |  | 	} else if (isError) { | 
					
						
							|  |  |  | 		content = <Error error={error} />; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		content = ( | 
					
						
							|  |  |  | 			<> | 
					
						
							| 
									
										
										
										
											2023-03-29 12:18:45 +02:00
										 |  |  | 				<EmojiList emoji={emoji} /> | 
					
						
							| 
									
										
										
										
											2023-01-25 09:47:55 +01:00
										 |  |  | 				<NewEmojiForm emoji={emoji} /> | 
					
						
							|  |  |  | 			</> | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 	return ( | 
					
						
							|  |  |  | 		<> | 
					
						
							| 
									
										
										
										
											2023-01-27 09:09:26 +01:00
										 |  |  | 			<h1>Local Custom Emoji</h1> | 
					
						
							|  |  |  | 			<p> | 
					
						
							|  |  |  | 				To use custom emoji in your toots they have to be 'local' to the instance. | 
					
						
							|  |  |  | 				You can either upload them here directly, or copy from those already | 
					
						
							| 
									
										
										
										
											2023-05-31 10:23:14 +02:00
										 |  |  | 				present on other (known) instances through the <Link to={`./remote`}>Remote Emoji</Link> page. | 
					
						
							| 
									
										
										
										
											2023-01-27 09:09:26 +01:00
										 |  |  | 			</p> | 
					
						
							| 
									
										
										
										
											2023-01-25 09:47:55 +01:00
										 |  |  | 			{content} | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 		</> | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-29 12:18:45 +02:00
										 |  |  | function EmojiList({ emoji }) { | 
					
						
							| 
									
										
										
										
											2023-01-27 09:09:26 +01:00
										 |  |  | 	const filterField = useTextInput("filter"); | 
					
						
							|  |  |  | 	const filter = filterField.value; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-25 15:49:48 +01:00
										 |  |  | 	const emojiByCategory = useEmojiByCategory(emoji); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-27 09:09:26 +01:00
										 |  |  | 	/* Filter emoji based on shortcode match with user input, hiding empty categories */ | 
					
						
							|  |  |  | 	const { filteredEmoji, hidden } = React.useMemo(() => { | 
					
						
							|  |  |  | 		let hidden = emoji.length; | 
					
						
							|  |  |  | 		const filteredEmoji = syncpipe(emojiByCategory, [ | 
					
						
							|  |  |  | 			(_) => Object.entries(emojiByCategory), | 
					
						
							|  |  |  | 			(_) => _.map(([category, entries]) => { | 
					
						
							|  |  |  | 				let filteredEntries = matchSorter(entries, filter, { keys: ["shortcode"] }); | 
					
						
							|  |  |  | 				if (filteredEntries.length == 0) { | 
					
						
							|  |  |  | 					return null; | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					hidden -= filteredEntries.length; | 
					
						
							|  |  |  | 					return [category, filteredEntries]; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}), | 
					
						
							|  |  |  | 			(_) => _.filter((value) => value !== null) | 
					
						
							|  |  |  | 		]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return { filteredEmoji, hidden }; | 
					
						
							|  |  |  | 	}, [filter, emojiByCategory, emoji.length]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 	return ( | 
					
						
							|  |  |  | 		<div> | 
					
						
							|  |  |  | 			<h2>Overview</h2> | 
					
						
							| 
									
										
										
										
											2023-01-27 09:09:26 +01:00
										 |  |  | 			{emoji.length > 0 | 
					
						
							|  |  |  | 				? <span>{emoji.length} custom emoji {hidden > 0 && `(${hidden} filtered)`}</span> | 
					
						
							|  |  |  | 				: <span>No custom emoji yet, you can add one below.</span> | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 			<div className="list emoji-list"> | 
					
						
							| 
									
										
										
										
											2023-01-27 09:09:26 +01:00
										 |  |  | 				<div className="header"> | 
					
						
							|  |  |  | 					<TextInput | 
					
						
							|  |  |  | 						field={filterField} | 
					
						
							|  |  |  | 						name="emoji-shortcode" | 
					
						
							|  |  |  | 						placeholder="Search" | 
					
						
							|  |  |  | 					/> | 
					
						
							|  |  |  | 				</div> | 
					
						
							|  |  |  | 				<div className="entries scrolling"> | 
					
						
							|  |  |  | 					{filteredEmoji.length > 0 | 
					
						
							|  |  |  | 						? ( | 
					
						
							|  |  |  | 							<div className="entries scrolling"> | 
					
						
							|  |  |  | 								{filteredEmoji.map(([category, entries]) => { | 
					
						
							| 
									
										
										
										
											2023-03-29 12:18:45 +02:00
										 |  |  | 									return <EmojiCategory key={category} category={category} entries={entries} />; | 
					
						
							| 
									
										
										
										
											2023-01-27 09:09:26 +01:00
										 |  |  | 								})} | 
					
						
							|  |  |  | 							</div> | 
					
						
							|  |  |  | 						) | 
					
						
							|  |  |  | 						: <div className="entry">No local emoji matched your filter.</div> | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				</div> | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 			</div> | 
					
						
							|  |  |  | 		</div> | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-29 12:18:45 +02:00
										 |  |  | function EmojiCategory({ category, entries }) { | 
					
						
							|  |  |  | 	const baseUrl = useBaseUrl(); | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 	return ( | 
					
						
							|  |  |  | 		<div className="entry"> | 
					
						
							|  |  |  | 			<b>{category}</b> | 
					
						
							|  |  |  | 			<div className="emoji-group"> | 
					
						
							|  |  |  | 				{entries.map((e) => { | 
					
						
							|  |  |  | 					return ( | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 						<Link key={e.id} to={`${baseUrl}/${e.id}`}> | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 							<a> | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 								<img src={e.url} alt={e.shortcode} title={`:${e.shortcode}:`} /> | 
					
						
							| 
									
										
										
										
											2022-11-08 17:51:44 +01:00
										 |  |  | 							</a> | 
					
						
							|  |  |  | 						</Link> | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 				})} | 
					
						
							|  |  |  | 			</div> | 
					
						
							|  |  |  | 		</div> | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | } |