Commit ca28827d authored by Ekanayake P.M.D.P IT18013610's avatar Ekanayake P.M.D.P IT18013610

Merge branch 'it18013610' into 'master'

It18013610

See merge request !10
parents 70363aeb 79c3cb92
...@@ -47,7 +47,6 @@ exports.requestAutomatedAnswer = async (req, res, next) => { ...@@ -47,7 +47,6 @@ exports.requestAutomatedAnswer = async (req, res, next) => {
*/ */
exports.getAutomatedAnswer = async (req, res, next) => { exports.getAutomatedAnswer = async (req, res, next) => {
const { qid } = req.params; const { qid } = req.params;
console.log('answer is here' + qid);
try { try {
const answer = await AutomatedAnswer.findOne({ question: qid }); const answer = await AutomatedAnswer.findOne({ question: qid });
if (!answer) { if (!answer) {
......
...@@ -44,8 +44,8 @@ exports.createQuestion = async (req, res, next) => { ...@@ -44,8 +44,8 @@ exports.createQuestion = async (req, res, next) => {
pythonScript.stdout.on('data', (data) => { pythonScript.stdout.on('data', (data) => {
console.log('DATA FROM PYTHON IS HERE' + data); console.log('DATA FROM PYTHON IS HERE' + data);
}); });
pythonScript.stdout.on('end', function () { pythonScript.stderr.on('data', (data) => {
console.log('PYTHON SCRIPT HAS BEEN ENDED'); console.log('PYTHON SCRIPT ERROR : ' + data);
}); });
} catch (error) { } catch (error) {
next(error); next(error);
......
...@@ -2,7 +2,6 @@ const app = require('./app'); ...@@ -2,7 +2,6 @@ const app = require('./app');
const mongoose = require('mongoose'); const mongoose = require('mongoose');
const config = require('./config'); const config = require('./config');
const connect = (url) => { const connect = (url) => {
return mongoose.connect(url, config.db.options); return mongoose.connect(url, config.db.options);
}; };
......
...@@ -62,7 +62,15 @@ const AutomatedAnswerSchema = mongoose.Schema({ ...@@ -62,7 +62,15 @@ const AutomatedAnswerSchema = mongoose.Schema({
{ {
type: String type: String
} }
] ],
isLoading: {
type: Boolean,
default: true
},
isComplete: {
type: Boolean,
default: false
}
}); });
module.exports = mongoose.model('AutomatedAnswer', AutomatedAnswerSchema); module.exports = mongoose.model('AutomatedAnswer', AutomatedAnswerSchema);
{ {
"name": "stackoverflow-api", "name": "probexpert-be",
"version": "1.0.0", "version": "1.0.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
......
{ {
"name": "stackoverflow-api", "name": "probexpert-be",
"version": "1.0.0", "version": "1.0.0",
"description": "Stackoverflow Clone Server", "description": "Probexpert backend",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"start": "node index.js", "start": "node index.js",
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
"Rest", "Rest",
"MERN" "MERN"
], ],
"author": "Salih Ozdemir", "author": "Dasun Ekanayake",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
......
import spacy
from collections import Counter
from string import punctuation
class keywords:
"""
A class to extract technical related keywords from a text
"""
def __init__(self, text):
"""
Initialize a keyword object
"""
self.text = text
self.spacy_nlp = spacy.load("en_core_web_lg")
def extract(self):
"""
Extract keywords from the text
"""
result = []
pos_tag = ["PROPN", "ADJ", "NOUN"]
doc = self.spacy_nlp(self.text.lower())
for token in doc:
if (
token.text in self.spacy_nlp.Defaults.stop_words
or token.text in punctuation
):
continue
if token.pos_ in pos_tag:
result.append(token.text)
return result
import certifi
ca = certifi.where()
DATABASE_URL_PROD = "mongodb+srv://admin2:admin12345@cluster0.u4vl4.mongodb.net/production?retryWrites=true&w=majority" DATABASE_URL_PROD = "mongodb+srv://admin2:admin12345@cluster0.u4vl4.mongodb.net/production?retryWrites=true&w=majority"
DATABASE_URL_DEV = "mongodb+srv://admin:admin1234@cluster0.u4vl4.mongodb.net/test?retryWrites=true&w=majority" DATABASE_URL_DEV = "mongodb+srv://admin:admin1234@cluster0.u4vl4.mongodb.net/test?retryWrites=true&w=majority"
...@@ -15,7 +18,7 @@ def get_database(): ...@@ -15,7 +18,7 @@ def get_database():
CONNECTION_STRING = ENV == "DEV" and DATABASE_URL_DEV or DATABASE_URL_PROD CONNECTION_STRING = ENV == "DEV" and DATABASE_URL_DEV or DATABASE_URL_PROD
# Create a connection using MongoClient. You can import MongoClient or use pymongo.MongoClient # Create a connection using MongoClient. You can import MongoClient or use pymongo.MongoClient
client = MongoClient(CONNECTION_STRING) client = MongoClient(CONNECTION_STRING, tlsCAFile=ca)
# Create the database for our example (we will use the same database throughout the tutorial # Create the database for our example (we will use the same database throughout the tutorial
return ENV == "DEV" and client["test"] or client["production"] return ENV == "DEV" and client["test"] or client["production"]
...@@ -3,15 +3,16 @@ from search_engine_parser import GoogleSearch ...@@ -3,15 +3,16 @@ from search_engine_parser import GoogleSearch
import re import re
class Github: class GithubData:
""" """
A class to manage the Github API. A class to manage the Github API.
""" """
def __init__(self): def __init__(self, title):
""" """
Initialize the Github API. Initialize the Github API.
""" """
print(title)
def get_github_resources(self, query): def get_github_resources(self, query):
""" """
......
...@@ -2,7 +2,7 @@ from youtube import Youtube ...@@ -2,7 +2,7 @@ from youtube import Youtube
from Medium import Medium from Medium import Medium
from Dev import DevTo from Dev import DevTo
from stof import STOF from stof import STOF
from Github import Github from github import GithubData
import sys import sys
from database import get_database from database import get_database
...@@ -17,7 +17,8 @@ def saveAnswer(ans_id, stackoverflow, videos, medium_r, dev_r, github_r): ...@@ -17,7 +17,8 @@ def saveAnswer(ans_id, stackoverflow, videos, medium_r, dev_r, github_r):
{"_id": ObjectId(ans_id)}, {"_id": ObjectId(ans_id)},
{ {
"$set": { "$set": {
"loading":False, "isLoading": False,
"isComplete": True,
"youtube": videos, "youtube": videos,
"stackoverflow": stackoverflow, "stackoverflow": stackoverflow,
"medium_articles": medium_r.get("blogs", []), "medium_articles": medium_r.get("blogs", []),
...@@ -29,18 +30,7 @@ def saveAnswer(ans_id, stackoverflow, videos, medium_r, dev_r, github_r): ...@@ -29,18 +30,7 @@ def saveAnswer(ans_id, stackoverflow, videos, medium_r, dev_r, github_r):
} }
}, },
) )
print(
{
"youtube": videos,
"stackoverflow": stackoverflow,
"medium_articles": medium_r["blogs"],
"dev_articles": dev_r["blogs"],
"medium_resources": medium_r["resources"],
"dev_resources": dev_r["resources"],
"github_repos": github_r["repos"],
"github_links": github_r["links"],
}
)
except NameError as err: except NameError as err:
print("ERRORRR") print("ERRORRR")
print(err) print(err)
...@@ -48,7 +38,7 @@ def saveAnswer(ans_id, stackoverflow, videos, medium_r, dev_r, github_r): ...@@ -48,7 +38,7 @@ def saveAnswer(ans_id, stackoverflow, videos, medium_r, dev_r, github_r):
if __name__ == "__main__": if __name__ == "__main__":
# title = input("Enter question title: ") # title = input("Enter question title: ")
title = sys.argv[1] title = sys.argv[1]
# "what are the benefits of using java for mobile app development over flutter" # "what are the benefits of using java for mobile app development over flutter"
tags = sys.argv[2] # ["flutter","java"] tags = sys.argv[2] # ["flutter","java"]
AUTO_ANS_ID = sys.argv[3] # "611feaff2c4db730e56d78e8" AUTO_ANS_ID = sys.argv[3] # "611feaff2c4db730e56d78e8"
...@@ -57,7 +47,7 @@ if __name__ == "__main__": ...@@ -57,7 +47,7 @@ if __name__ == "__main__":
medium = Medium(title, tags) medium = Medium(title, tags)
devto = DevTo(title, tags) devto = DevTo(title, tags)
youtube = Youtube(title, tags) youtube = Youtube(title, tags)
github = Github() github = GithubData(title)
ans = stack.searchQuestion() ans = stack.searchQuestion()
medium_articels = medium.getMediumArticles() medium_articels = medium.getMediumArticles()
dev_articles = devto.get_dev_articles() dev_articles = devto.get_dev_articles()
......
...@@ -73,7 +73,14 @@ class STOF: ...@@ -73,7 +73,14 @@ class STOF:
# print(soup.prettify().encode("utf-8")) # print(soup.prettify().encode("utf-8"))
return answer return answer
def calculateAccuracy(self): def calculateAccuracy(self):
""" """
Compare the user's question with stackoverflow question and calculate the accuracy Compare the user's question with stackoverflow question and calculate the accuracy
""" """
\ No newline at end of file pass
def get_clean_url(url):
import re
pattern = r"^.*?\&sa="
return re.match(pattern, url).group(0)
...@@ -27,3 +27,4 @@ class Youtube: ...@@ -27,3 +27,4 @@ class Youtube:
videos.append(i["link"]) videos.append(i["link"])
print(i["link"]) print(i["link"])
return videos return videos
\ No newline at end of file
...@@ -9,6 +9,7 @@ import styles from './automated-answer-container.module.css' ...@@ -9,6 +9,7 @@ import styles from './automated-answer-container.module.css'
const AutomatedAnswerContainer = ({ question_id }) => { const AutomatedAnswerContainer = ({ question_id }) => {
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [answer, setAnswer] = useState() const [answer, setAnswer] = useState()
const [isAnswerGenerating, setIsAnswertGenerating] = useState(false)
const [error, setError] = useState({ const [error, setError] = useState({
status: '', status: '',
action: '', action: '',
...@@ -20,8 +21,16 @@ const AutomatedAnswerContainer = ({ question_id }) => { ...@@ -20,8 +21,16 @@ const AutomatedAnswerContainer = ({ question_id }) => {
const fetchAutomatedAnswer = async () => { const fetchAutomatedAnswer = async () => {
try { try {
const response = await publicFetch.get(`automatedanswer/${question_id}`) const response = await publicFetch.get(`automatedanswer/${question_id}`)
if (response.status == 200) setAnswer(response.data) if (response.status == 200) {
else setServerError({ response }) console.log('RESPONSE IS HERE AND IT IS')
const { isLoading, isComplete } = response.data.automatedanswer
if (isLoading && !isComplete) {
setIsAnswertGenerating(true)
setServerError(102)
} else {
setAnswer(response.data)
}
} else setServerError({ response })
} catch (error) { } catch (error) {
setServerError(error) setServerError(error)
} }
...@@ -31,7 +40,14 @@ const AutomatedAnswerContainer = ({ question_id }) => { ...@@ -31,7 +40,14 @@ const AutomatedAnswerContainer = ({ question_id }) => {
}, [question_id]) }, [question_id])
const setServerError = (error) => { const setServerError = (error) => {
if (error.response.status == 404) { if (error == 102) {
setError({
status: '102',
action: 'loading',
button: 'Answer is generatingg',
message: 'Automated answer 🤖 is generating in the backend '
})
} else if (error.response.status == 404) {
setError({ setError({
status: '404', status: '404',
action: 'create', action: 'create',
...@@ -48,6 +64,30 @@ const AutomatedAnswerContainer = ({ question_id }) => { ...@@ -48,6 +64,30 @@ const AutomatedAnswerContainer = ({ question_id }) => {
} }
} }
const getBody = () => {
if (loading) {
return <Spinner className={styles.spinner} />
} else if (isAnswerGenerating) {
return (
<NoAutomatedAnswer
question_id={question_id}
error={error}
isGenerating={true}
/>
)
} else if (answer != null) {
return <AutomatedAnswer automatedAnswer={answer.automatedanswer} />
} else {
return (
<NoAutomatedAnswer
question_id={question_id}
error={error}
isGenerating={false}
/>
)
}
}
return ( return (
<div className={styles.container}> <div className={styles.container}>
<div className={styles.header}> <div className={styles.header}>
...@@ -55,15 +95,7 @@ const AutomatedAnswerContainer = ({ question_id }) => { ...@@ -55,15 +95,7 @@ const AutomatedAnswerContainer = ({ question_id }) => {
<h2>Automated Answer</h2> <h2>Automated Answer</h2>
</div> </div>
</div> </div>
<div className={styles.wrapper}> <div className={styles.wrapper}>{getBody()}</div>
{loading ? (
<Spinner className={styles.spinner} />
) : answer != null ? (
<AutomatedAnswer automatedAnswer={answer.automatedanswer} />
) : (
<NoAutomatedAnswer question_id={question_id} error={error} />
)}
</div>
</div> </div>
) )
} }
......
import React from 'react' import React from 'react'
import BlogsWrapper from '../blogs-wrapper/BlogsWrapper'
import StackOverflowAnswer from '../stof-answer' import StackOverflowAnswer from '../stof-answer'
import YoutubeVideoWrapper from '../youtube-videos/YoutubeVideoWrapper' import YoutubeVideoWrapper from '../youtube-videos/YoutubeVideoWrapper'
...@@ -18,6 +19,18 @@ const AutomatedAnswer = ({ automatedAnswer }) => { ...@@ -18,6 +19,18 @@ const AutomatedAnswer = ({ automatedAnswer }) => {
) : ( ) : (
<h1>No youtubes found for this question</h1> <h1>No youtubes found for this question</h1>
)} )}
<BlogsWrapper
source="Medium"
articles={automatedAnswer.medium_articles}
resources={automatedAnswer.medium_resources}
/>
<BlogsWrapper
source="Dev.to"
articles={automatedAnswer.dev_articles}
resources={automatedAnswer.dev_resources}
/>
</> </>
) )
} }
......
import React from 'react' import React, { useContext } from 'react'
import { FetchContext } from '../../../store/fetch'
import styles from './no-automated-answer.module.css' import styles from './no-automated-answer.module.css'
const NoAutomatedAnswer = ({ question_id, error }) => { import { Spinner } from '../../icons'
const NoAutomatedAnswer = ({ question_id, error, isGenerating }) => {
const { authAxios } = useContext(FetchContext)
const { status, action, button, message } = error const { status, action, button, message } = error
return ( return (
<div className={styles.no_automated_answer}> <div className={styles.no_automated_answer}>
<h1 className={styles.title}>{message}</h1> <h1 className={styles.title}>{message}</h1>
<button className={styles.generate_btn}>{button}</button> {isGenerating ? (
<Spinner className={styles.spinner} />
) : (
<button className={styles.generate_btn}>{button}</button>
)}
</div> </div>
) )
} }
......
...@@ -17,3 +17,10 @@ ...@@ -17,3 +17,10 @@
font-size: 1.5em; font-size: 1.5em;
text-align: center; text-align: center;
} }
.spinner {
display: flex;
margin: auto;
height: 3em;
width: 3em;
}
import React from 'react'
import styles from './BlogArticle.module.css'
const BlogArticle = ({ article }) => {
const createMarkup = () => {
return { __html: article.description }
}
return (
<div className={styles.blog_article}>
<span className={styles.title}>{article.title}</span>
<div
className={styles.description}
dangerouslySetInnerHTML={createMarkup()}
></div>
</div>
)
}
export default BlogArticle
.blog_article {
margin: 1em 0;
overflow: hidden;
}
.title {
display: block;
font-size: 2em;
text-align: center;
margin: 10px 0;
}
.description {
width: 100%;
/* blockquote {
--reach-tabs: 1;
--reach-menu-button: 1;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
color: white;
font-family: medium-content-sans-serif-font, -apple-system,
BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell,
'Open Sans', 'Helvetica Neue', sans-serif;
font-weight: 400;
word-break: break-word;
word-wrap: break-word;
box-sizing: inherit;
margin: 0;
box-shadow: inset 3px 0 0 0 rgba(41, 41, 41, 1);
padding-left: 23px;
margin-left: -20px;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
word-wrap: break-word;
box-sizing: inherit;
margin: 0;
font-weight: 400;
word-break: break-word;
font-style: italic;
font-family: charter, Georgia, Cambria, 'Times New Roman', Times, serif;
margin-bottom: -0.46em;
font-size: 21px;
margin-top: 2em;
line-height: 32px;
letter-spacing: -0.003em;
strong {
--reach-tabs: 1;
--reach-menu-button: 1;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
word-wrap: break-word;
word-break: break-word;
color: white;
font-style: italic;
font-size: 21px;
line-height: 32px;
letter-spacing: -0.003em;
box-sizing: inherit;
font-family: charter, Georgia, Cambria, 'Times New Roman', Times, serif;
font-weight: 700;
}
} */
* {
width: 100%;
overflow: hidden;
}
img {
width: 100%;
}
figure {
img {
width: 100%;
}
figcaption {
font-size: 0.8em;
text-align: center;
color: var(--black-200);
}
}
p {
margin: 20px 0;
font-size: 1.2em;
}
pre {
padding: 20px;
background-color: var(black);
font-size: 1.1em;
font-family: 'Roboto Mono', monospace !important;
}
pre::first-line {
font-weight: bold;
}
ul {
margin-left: 10px;
padding: 0;
list-style: none;
list-style-image: none;
font-size: 1.1em;
li {
letter-spacing: -0.003em;
line-height: 32px;
margin-left: 30px;
/* margin-top: 2em; */
list-style: inside;
list-style-type: disc !important;
margin-bottom: -0.46em;
}
}
h4 {
font-size: 1.3em;
margin: 10px 0;
}
h3 {
font-size: 1.4em !important;
margin: 20px 0 10px 0;
}
a {
color: var(--blue-300);
}
a:hover {
color: var(--blue-600);
}
}
import React, { useState } from 'react'
import AutomatedAnswerSwiper from '../automated-answer-swiper/AutomatedAnswerSwiper'
import BlogArticle from '../blog-article/BlogArticle'
import ShowHide from '../show-hide/ShowHide'
import styles from './BlogsWrapper.module.css'
const BlogsWrapper = ({ source, articles, resources }) => {
const [show, setShow] = useState(false)
return (
<>
{articles && articles.length > 0 ? (
<>
<h1 className={styles.h1}>
Here {articles.length > 1 ? 'are' : 'is'} {articles.length} article
{articles.length > 1 && 's'} I found on {source}
<ShowHide show={show} onClick={() => setShow(!show)} />
</h1>
{show && (
<div className={styles.blogs_wrapper}>
<AutomatedAnswerSwiper>
{articles.map((article, i) => {
return <BlogArticle key={i} article={article} />
})}
</AutomatedAnswerSwiper>
</div>
)}
</>
) : (
<h1>
No {source} articles found for this question. Please refer the extra
resouces to find more info
</h1>
)}
</>
)
}
export default BlogsWrapper
.blogs_wrapper {
margin-top: 0.5em;
background-color: #2d2d2d;
padding: 0.8em;
border-radius: 2px;
margin-bottom: 3em;
width: 100%;
overflow: hidden;
}
.h1 {
font-size: 2em !important;
display: flex;
justify-content: space-between;
align-items: center;
}
import React from 'react'
const EyeIcon = ({ width, height, color }) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
id="Capa_1"
width={width}
height={height}
fill={color}
viewBox="0 0 511.992 511.992"
enableBackground="new 0 0 512 512"
>
<g>
<g>
<path d="M510.096,249.937c-4.032-5.867-100.928-143.275-254.101-143.275C124.56,106.662,7.44,243.281,2.512,249.105 c-3.349,3.968-3.349,9.792,0,13.781C7.44,268.71,124.56,405.329,255.995,405.329S504.549,268.71,509.477,262.886 C512.571,259.217,512.848,253.905,510.096,249.937z M255.995,383.996c-105.365,0-205.547-100.48-230.997-128 c25.408-27.541,125.483-128,230.997-128c123.285,0,210.304,100.331,231.552,127.424 C463.013,282.065,362.256,383.996,255.995,383.996z" />
</g>
</g>
<g>
<g>
<path d="M255.995,170.662c-47.061,0-85.333,38.272-85.333,85.333s38.272,85.333,85.333,85.333s85.333-38.272,85.333-85.333 S303.056,170.662,255.995,170.662z M255.995,319.996c-35.285,0-64-28.715-64-64s28.715-64,64-64s64,28.715,64,64 S291.28,319.996,255.995,319.996z" />
</g>
</g>
</svg>
)
}
export default EyeIcon
import React from 'react'
const EyeCloseIcon = ({ width, height, color }) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
id="Capa_1"
width={width}
height={height}
fill={color}
viewBox="0 0 511.992 511.992"
enableBackground="new 0 0 512 512"
>
<g>
<g>
<path d="M316.332,195.662c-4.16-4.16-10.923-4.16-15.083,0c-4.16,4.16-4.16,10.944,0,15.083 c12.075,12.075,18.752,28.139,18.752,45.248c0,35.285-28.715,64-64,64c-17.109,0-33.173-6.656-45.248-18.752 c-4.16-4.16-10.923-4.16-15.083,0c-4.16,4.139-4.16,10.923,0,15.083c16.085,16.128,37.525,25.003,60.331,25.003 c47.061,0,85.333-38.272,85.333-85.333C341.334,233.187,332.46,211.747,316.332,195.662z" />
</g>
</g>
<g>
<g>
<path d="M270.87,172.131c-4.843-0.853-9.792-1.472-14.869-1.472c-47.061,0-85.333,38.272-85.333,85.333 c0,5.077,0.619,10.027,1.493,14.869c0.917,5.163,5.419,8.811,10.475,8.811c0.619,0,1.237-0.043,1.877-0.171 c5.781-1.024,9.664-6.571,8.64-12.352c-0.661-3.627-1.152-7.317-1.152-11.157c0-35.285,28.715-64,64-64 c3.84,0,7.531,0.491,11.157,1.131c5.675,1.152,11.328-2.859,12.352-8.64C280.534,178.702,276.652,173.155,270.87,172.131z" />
</g>
</g>
<g>
<g>
<path d="M509.462,249.102c-2.411-2.859-60.117-70.208-139.712-111.445c-5.163-2.709-11.669-0.661-14.379,4.587 c-2.709,5.227-0.661,11.669,4.587,14.379c61.312,31.744,110.293,81.28,127.04,99.371c-25.429,27.541-125.504,128-230.997,128 c-35.797,0-71.872-8.64-107.264-25.707c-5.248-2.581-11.669-0.341-14.229,4.971c-2.581,5.291-0.341,11.669,4.971,14.229 c38.293,18.496,77.504,27.84,116.523,27.84c131.435,0,248.555-136.619,253.483-142.443 C512.854,258.915,512.833,253.091,509.462,249.102z" />
</g>
</g>
<g>
<g>
<path d="M325.996,118.947c-24.277-8.171-47.829-12.288-69.995-12.288c-131.435,0-248.555,136.619-253.483,142.443 c-3.115,3.669-3.371,9.003-0.597,12.992c1.472,2.112,36.736,52.181,97.856,92.779c1.813,1.216,3.84,1.792,5.888,1.792 c3.435,0,6.827-1.664,8.875-4.8c3.264-4.885,1.92-11.52-2.987-14.763c-44.885-29.845-75.605-65.877-87.104-80.533 c24.555-26.667,125.291-128.576,231.552-128.576c19.861,0,41.131,3.755,63.189,11.157c5.589,2.005,11.648-1.088,13.504-6.699 C334.572,126.862,331.585,120.825,325.996,118.947z" />
</g>
</g>
<g>
<g>
<path d="M444.865,67.128c-4.16-4.16-10.923-4.16-15.083,0L67.116,429.795c-4.16,4.16-4.16,10.923,0,15.083 c2.091,2.069,4.821,3.115,7.552,3.115c2.731,0,5.461-1.045,7.531-3.115L444.865,82.211 C449.025,78.051,449.025,71.288,444.865,67.128z" />
</g>
</g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
</svg>
)
}
export default EyeCloseIcon
...@@ -11,7 +11,7 @@ const Pagination = ({ ...@@ -11,7 +11,7 @@ const Pagination = ({
return ( return (
<div className={styles.pagination_wrapper}> <div className={styles.pagination_wrapper}>
<span onClick={onClickFirst} className={styles.cursor}> <span onClick={onClickFirst} className={styles.cursor}>
first &lt;&lt;
</span> </span>
<div className={styles.numbering}> <div className={styles.numbering}>
{new Array(length).fill(0).map((item, index) => { {new Array(length).fill(0).map((item, index) => {
...@@ -33,7 +33,7 @@ const Pagination = ({ ...@@ -33,7 +33,7 @@ const Pagination = ({
<span className={styles.muted_number}>{length}</span> */} <span className={styles.muted_number}>{length}</span> */}
</div> </div>
<span onClick={onClickLast} className={styles.cursor}> <span onClick={onClickLast} className={styles.cursor}>
last &gt;&gt;
</span> </span>
</div> </div>
) )
......
.pagination_wrapper { .pagination_wrapper {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: center;
align-items: center;
} }
.numbering { .numbering {
...@@ -27,5 +28,10 @@ ...@@ -27,5 +28,10 @@
} }
.cursor { .cursor {
margin: 0 10px;
cursor: pointer; cursor: pointer;
color: #fff;
padding: 4px 10px;
background-color: #2d2d2d;
border: 1px solid #78ff78;
} }
...@@ -10,7 +10,6 @@ import Textarea from '../../textarea' ...@@ -10,7 +10,6 @@ import Textarea from '../../textarea'
import FormInput from '../../form-input' import FormInput from '../../form-input'
import TagInput from '../../tag-input' import TagInput from '../../tag-input'
import SimilarQuestionSuggestions from '../../similar-question-suggestions' import SimilarQuestionSuggestions from '../../similar-question-suggestions'
import styles from './question-form.module.css' import styles from './question-form.module.css'
const QuestionForm = () => { const QuestionForm = () => {
......
import React from 'react'
import EyeIcon from '../icons/Eye'
import EyeCloseIcon from '../icons/EyeClose'
import styles from './ShowHide.module.css'
const ShowHide = ({ onClick, show }) => {
return (
<div onClick={onClick} className={styles.show_hide}>
{show ? (
<span>
<EyeCloseIcon width={24} height={24} color="red" /> Hide
</span>
) : (
<span>
<EyeIcon width={24} height={24} color="white" /> Show
</span>
)}
</div>
)
}
export default ShowHide
.show_hide {
cursor: pointer;
font-size: 1.5rem;
background-color: var(--black-800);
padding: 2px 10px;
border-radius: 5px;
span {
display: flex;
align-items: center;
* {
margin-right: 5px;
}
}
}
...@@ -29,6 +29,5 @@ ...@@ -29,6 +29,5 @@
--powder-700: #39739d; --powder-700: #39739d;
--powder-800: #2c5777; --powder-800: #2c5777;
--main-purple: #800080; --main-purple: #800080;
--fade: 120ms; --fade: 120ms;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment