diff --git a/react/src/helpers/challenges.ts b/react/src/helpers/challenges.ts index b58e10152..5e9742c9c 100644 --- a/react/src/helpers/challenges.ts +++ b/react/src/helpers/challenges.ts @@ -423,4 +423,15 @@ export const challenges = new Map([ tags: [], }, ], + [ + 'emoji-picker', + { + title: 'Emoji Picker', + link: 'emoji-picker', + difficulty: 'medium', + developer: 'jeevaramanathan', + tags: [], + isNew:true + }, + ], ]); diff --git a/react/src/helpers/contributors.ts b/react/src/helpers/contributors.ts index 5eb430987..4db28e3f4 100644 --- a/react/src/helpers/contributors.ts +++ b/react/src/helpers/contributors.ts @@ -28,5 +28,6 @@ export const contributors = new Map([ ['viditagrawal56', { name: 'Vidit Agrawal', pic: 'https://avatars.githubusercontent.com/u/52532308' }], ['Bhushan1019', { name: 'Bhushan Patil', pic: 'https://avatars.githubusercontent.com/u/121352274' }], ['Sumitwarrior7', { name: 'Cool Dude 69', pic: 'https://avatars.githubusercontent.com/u/108853577' }], - ['rishabhm05', {name:'Rishabh Mehta', pic:'https://avatars.githubusercontent.com/u/67910259'}] + ['rishabhm05', {name:'Rishabh Mehta', pic:'https://avatars.githubusercontent.com/u/67910259'}], + ['jeevaramanathan', {name:'Jeeva Ramanathan', pic:'https://avatars.githubusercontent.com/u/64531160'}] ]); diff --git a/react/src/machine-coding/emoji-picker/App.jsx b/react/src/machine-coding/emoji-picker/App.jsx new file mode 100644 index 000000000..c6a8d6365 --- /dev/null +++ b/react/src/machine-coding/emoji-picker/App.jsx @@ -0,0 +1,12 @@ +import styles from "./app.module.css" +import Emoji from './Emoji'; +import Code from './Code' +export default function App() { + + return ( +
+ + +
+ ); +} diff --git a/react/src/machine-coding/emoji-picker/Code.jsx b/react/src/machine-coding/emoji-picker/Code.jsx new file mode 100644 index 000000000..77766116d --- /dev/null +++ b/react/src/machine-coding/emoji-picker/Code.jsx @@ -0,0 +1,62 @@ +import React from 'react'; +import styles from './app.module.css'; + +const obj = ` + **Main Functionalities** + + + **Copy Block level(div) elements to clipboard** +function copyToClipboard(element) { + // Create a range object that selects the element \n + // to be copied. + const range = document.createRange(); + range.selectNode(element); + + // clear current selection + window.getSelection().removeAllRanges(); + + // Selects the given range. + window.getSelection().addRange(range); + + // Copy the selection to the clipboard. + document.execCommand('copy'); + + // Remove the range from the selection. + selection.removeAllRanges(); +} + + + **Filter emojis based on search value** +emojis.filter((icon) => { + icon.toLowerCase().includes(searchValue.toLowerCase()) +}) + + + **axios to call API** +axios.get(__url__) + .then(response => { + // Handle response + }); +`; + +const Code = () => { + return ( +
+
+      
+        {obj.split('\n').map((line, index) => {
+          if (line.trim().startsWith('//')) {
+            return {line};
+          }
+          else if(line.trim().startsWith('**')){
+            return {line};  
+          }
+          return 
{line}
; + })} +
+
+
+ ); +}; + +export default Code; \ No newline at end of file diff --git a/react/src/machine-coding/emoji-picker/Emoji.jsx b/react/src/machine-coding/emoji-picker/Emoji.jsx new file mode 100644 index 000000000..87aed391a --- /dev/null +++ b/react/src/machine-coding/emoji-picker/Emoji.jsx @@ -0,0 +1,125 @@ +import { useEffect, useState } from 'react'; +import styles from './app.module.css'; +import axios from 'axios'; + +const access_key = 'eb3aa13df1b14cc7bc614fc2d7f894f41b09d68a'; +const Emoji = () => { + const [emojis, setEmojis] = useState([]); + const [filteredEmojis, setFilteredEmojis] = useState([]); + const [search, setSearch] = useState(''); + const [toastMessage, setToastMessage] = useState(''); + const [category, setCategory] = useState([]); + + useEffect(() => { + loadAllEmojis(); + loadCategories(); + window.scrollTo(0,0); + }, []); + + const loadAllEmojis = () => { + axios.get(`https://emoji-api.com/emojis?access_key=${access_key}`).then((res) => { + setEmojis(res.data); + setFilteredEmojis(res.data); + }); + }; + + const loadCategories = () => { + axios.get(`https://emoji-api.com/categories?access_key=${access_key}`).then((res) => { + setCategory(res.data); + }); + }; + + const getIconTitle = (title) => { + const [_, ...value] = title.split(' '); + return value.join(' '); + }; + + const onChange = (e) => { + let searchValue = e.target.value; + setSearch(searchValue); + let filteredIcons = emojis.filter((icon) => + icon.unicodeName.toLowerCase().includes(searchValue.trim().toLowerCase()) + ); + setFilteredEmojis(filteredIcons); + }; + + const categoryChange = (e) => { + setSearch(''); + setFilteredEmojis([]); + setEmojis([]); + if (e.target.value == 'all') { + loadAllEmojis(); + } else { + axios.get(`https://emoji-api.com/categories/${e.target.value}?access_key=${access_key}`).then((res) => { + setEmojis(res.data); + setFilteredEmojis(res.data); + }); + } + }; + + const copyToClipBoard = (id) => { + let range = document.createRange(); + range.selectNode(document.getElementById(id)); + window.getSelection().removeAllRanges(); // clear current selection + window.getSelection().addRange(range); // to select text + document.execCommand('copy'); + window.getSelection().removeAllRanges(); // to deselect + setToastMessage('Copied Successfully!'); + setTimeout(() => { + setToastMessage(''); + }, 1500); + }; + + return ( + <> +
+
+ +
+
+ +
+
+ Click on an Emoji to Copy +
+
+
+ {filteredEmojis?.length == 0 && search.trim() == '' && ( +
+
+
+ )} + {filteredEmojis?.map((icon, index) => ( + copyToClipBoard(icon.unicodeName + '_' + index)} + > + + {icon.character} + + + ))} +
+ + {toastMessage &&
{toastMessage}
} + + ); +}; + +export default Emoji; diff --git a/react/src/machine-coding/emoji-picker/app.module.css b/react/src/machine-coding/emoji-picker/app.module.css new file mode 100644 index 000000000..bf7e0f0d7 --- /dev/null +++ b/react/src/machine-coding/emoji-picker/app.module.css @@ -0,0 +1,178 @@ +/* app */ +.main { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; +} + +/* emoji component */ +.container { + height: 400px; + width: 100%; + background-color: rgb(249, 249, 249); + border-radius: 3px; + box-shadow: 0 0 3px 2px rgba(201, 201, 201, 0.933); + overflow-x: hidden; + overflow-y: scroll; + padding: 10px; + margin: 26px; +} + +.container::-webkit-scrollbar, +.container::-webkit-scrollbar-thumb { + border-radius: 13px; + width: 13px; + height: 40px; +} + +.container::-webkit-scrollbar-thumb { + box-shadow: inset 10px 10px 10px 5px rgb(184, 184, 184); +} + +.iconContainer { + height: 30%; + width: 30%; +} + +.icon { + display: inline-block; + width: calc(100% / 3); + padding: 1px; + text-align: center; + font-size: 30px; + border: 3px solid transparent; + border-radius: 10px; + transition: border-color 0.3s; + cursor: pointer; +} + +.icon:hover { + border-color: rgb(217, 217, 217); +} + +.inputField { + padding: 10px; + margin-bottom: 10px; + font-size: 16px; + border: 1px solid #ccc; + border-radius: 5px; + border: 2px solid rgb(80, 66, 0); +} +.inputField:hover { + cursor: auto; + border: 2px solid rgb(80, 66, 0); +} +.toast { + position: fixed; + top: 20px; + width: 300px; + height: 30px; + background-color: rgb(128, 238, 128); + border-radius: 20px; + box-shadow: 0 0 3px 2px rgba(201, 201, 201, 0.933); + color: darkslategray; + text-align: center; + display: flex; + align-items: center; + justify-content: center; +} + +.loader { + border: 6px solid #f3f3f3; + border-top: 6px solid #3498db; + border-radius: 50%; + width: 60px; + height: 60px; + animation: spin 2s linear infinite; +} + +.loaderContainer { + display: flex; + justify-content: center; +} + +.topSection { + display: flex; + justify-content: center; + flex-direction: column; +} + +.select { + padding: 10px; + margin-left: 20px; + width: 180px; + margin-bottom: 10px; + font-size: 16px; + border: 1px solid #ccc; + border-radius: 5px; + border: 2px solid rgb(80, 66, 0); + font-size: 14px; +} + +.copyText { + font-size: small; + text-align: center; + color: #bababa; + opacity: 1; +} + +.hidden { + opacity: 0; +} + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +@media (max-width: 576px) { + .icon { + width: calc(100% / 6); + } +} + +@media (min-width: 768px) { + .icon { + width: calc(100% / 8); + } + .container { + width: 500px; + } +} + +@media (min-width: 992px) { + .icon { + width: calc(100% / 10); + } + .container { + width: 500px; + } +} + + +/* code component */ +pre { + background: #eee; + padding: 1rem; + overflow: auto; + border-radius: 3px; + max-width: 80ch; +} + +pre code { + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; +} + +.comments { + color: green; +} diff --git a/react/src/pages/Challenge.tsx b/react/src/pages/Challenge.tsx index 75f6c8ef2..5fbc49024 100644 --- a/react/src/pages/Challenge.tsx +++ b/react/src/pages/Challenge.tsx @@ -37,6 +37,7 @@ import TwentyfiveFiveClock from '@/machine-coding/25-5-clock'; import WordCounter from '@/machine-coding/word-count'; import YourSport from '@/machine-coding/your-sport'; import ModalPopup from '@/machine-coding/modal-popup/App'; +import EmojiPicker from '@/machine-coding/emoji-picker/App'; import ProgrammingLanguageMultiverse from '@/machine-coding/programming-languages-multiverse'; import { challenges } from '@/helpers/challenges'; import { useParams } from 'react-router-dom'; @@ -79,7 +80,8 @@ const reactChallenges = { 'color-mixer': , 'string-transformers': , 'your-sport': , - 'modal-popup': , + 'modal-popup':, + 'emoji-picker':, 'programming-languages-multiverse': , };