Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
2
2021-155
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
2021-155
2021-155
Commits
7963cda7
Commit
7963cda7
authored
Jul 03, 2021
by
Ekanayake P.M.D.P IT18013610
☺
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'it18013610' into 'master'
It18013610 See merge request
!8
parents
d49badaa
f2718707
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
355 additions
and
92 deletions
+355
-92
backend/models/automatedAnswer.js
backend/models/automatedAnswer.js
+31
-3
backend/models/blogArticle.js
backend/models/blogArticle.js
+0
-22
backend/python/auto-answer/Dev.py
backend/python/auto-answer/Dev.py
+75
-0
backend/python/auto-answer/Medium.py
backend/python/auto-answer/Medium.py
+92
-54
backend/python/auto-answer/requirements.txt
backend/python/auto-answer/requirements.txt
+3
-1
backend/python/auto-answer/scrapper.py
backend/python/auto-answer/scrapper.py
+29
-9
backend/requirements.txt
backend/requirements.txt
+1
-0
client/components/automated-answer/index.js
client/components/automated-answer/index.js
+8
-0
client/components/stof-answer/index.js
client/components/stof-answer/index.js
+3
-1
client/components/stof-answer/stof-answer.module.css
client/components/stof-answer/stof-answer.module.css
+3
-1
client/components/youtube-videos/YoutubeVideoWrapper.js
client/components/youtube-videos/YoutubeVideoWrapper.js
+20
-0
client/components/youtube-videos/YoutubeVideoWrapper.module.css
.../components/youtube-videos/YoutubeVideoWrapper.module.css
+10
-0
client/components/youtube-videos/youtube-video/YoutubeVideo.js
...t/components/youtube-videos/youtube-video/YoutubeVideo.js
+20
-0
client/components/youtube-videos/youtube-video/YoutubeVideo.module.css
...ents/youtube-videos/youtube-video/YoutubeVideo.module.css
+15
-0
client/styles/automatedanswer.css
client/styles/automatedanswer.css
+45
-1
No files found.
backend/models/automatedAnswer.js
View file @
7963cda7
...
@@ -29,10 +29,38 @@ const AutomatedAnswerSchema = mongoose.Schema({
...
@@ -29,10 +29,38 @@ const AutomatedAnswerSchema = mongoose.Schema({
type
:
String
type
:
String
}
}
],
],
blog
s
:
[
medium_article
s
:
[
{
{
type
:
Schema
.
Types
.
ObjectId
,
title
:
String
,
ref
:
'
BlogArticle
'
pubDate
:
String
,
link
:
String
,
guid
:
String
,
author
:
String
,
thumbnail
:
String
,
description
:
String
,
content
:
String
}
],
dev_articles
:
[
{
title
:
String
,
pubDate
:
String
,
link
:
String
,
guid
:
String
,
author
:
String
,
thumbnail
:
String
,
description
:
String
,
content
:
String
}
],
medium_resources
:
[
{
type
:
String
}
],
dev_resources
:
[
{
type
:
String
}
}
]
]
});
});
...
...
backend/models/blogArticle.js
deleted
100644 → 0
View file @
d49badaa
const
mongoose
=
require
(
'
mongoose
'
);
const
BlogArticleSchema
=
mongoose
.
Schema
({
automatedAnswer
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
'
AutomatedAnswer
'
,
required
:
true
},
blogName
:
{
type
:
String
,
required
:
true
},
link
:
{
type
:
String
,
required
:
true
},
content
:
{
type
:
String
}
});
module
.
exports
=
mongoose
.
model
(
'
BlogArticle
'
,
BlogArticleSchema
);
backend/python/auto-answer/Dev.py
0 → 100644
View file @
7963cda7
from
search_engine_parser
import
GoogleSearch
import
re
import
requests
import
random
class
DevTo
:
def
__init__
(
self
,
title
,
tags
):
self
.
title
=
title
self
.
tags
=
tags
def
getApiKey
(
self
):
api_keys
=
[
"2rk1eg4sexdnp5umrwtwbtwd2insqvgzvejooqrn"
,
"yit6ytfcs3ziawdgasfd3bgkbf4tef1m2nzdxvnz"
,
"mpawymyrc6derrwmgodowfsaabtuoes4iiwintd7"
,
]
return
random
.
choice
(
api_keys
)
def
google
(
self
,
query
):
search_args
=
(
query
,
1
)
gsearch
=
GoogleSearch
()
gresults
=
gsearch
.
search
(
*
search_args
)
return
gresults
[
"links"
]
def
getValidUrls
(
self
,
links
):
validUrls
=
[]
for
i
in
links
:
if
"dev.to"
in
i
:
uriTrimmed
=
re
.
match
(
r"^.*?\&sa="
,
i
[
29
:])
.
group
(
0
)
ur
=
uriTrimmed
.
replace
(
"&sa="
,
""
)
validUrls
.
append
(
ur
)
return
validUrls
def
getValidSets
(
self
,
validUrls
):
validSets
=
[]
for
url
in
validUrls
:
try
:
vset
=
{}
print
(
url
)
username
=
re
.
search
(
r"https://dev.to/([^/?]+)"
,
url
)
.
group
(
1
)
tag
=
re
.
search
(
r"https://dev.to/([^/?]+)/([^/?]+)"
,
url
)
.
group
(
2
)
vset
[
"username"
]
=
username
vset
[
"tag"
]
=
tag
validSets
.
append
(
vset
)
except
Exception
as
e
:
print
(
e
)
continue
return
validSets
def
getBlogs
(
self
,
username
,
tag
):
blog
=
{}
try
:
response
=
requests
.
get
(
f
"https://api.rss2json.com/v1/api.json?rss_url=https
%3
A
%2
F
%2
Fdev.to
%2
Ffeed
%2
F{username}&api_key={self.getApiKey()}"
)
if
response
.
status_code
==
200
:
res
=
response
.
json
()
for
item
in
res
[
"items"
]:
if
tag
in
item
[
"link"
]:
blog
=
item
except
Exception
as
e
:
print
(
e
)
return
blog
def
getDevArticles
(
self
):
links
=
self
.
google
(
f
"site:dev.to {self.title} after:2020-01-01"
)
validUrls
=
self
.
getValidUrls
(
links
)
validSets
=
self
.
getValidSets
(
validUrls
)
blogs
=
[]
for
validset
in
validSets
:
blog
=
self
.
getBlogs
(
validset
[
"username"
],
validset
[
"tag"
])
if
bool
(
blog
):
blogs
.
append
(
blog
)
return
{
"blogs"
:
blogs
,
"resources"
:
validUrls
}
backend/python/auto-answer/Medium.py
View file @
7963cda7
import
requests
import
json
from
requests_html
import
HTMLSession
from
search_engine_parser
import
GoogleSearch
from
bs4
import
BeautifulSoup
import
re
import
re
from
lxml
import
etree
import
requests
import
random
class
Medium
:
class
Medium
:
def
__init__
(
self
,
qtitle
,
keywords
=
[],
description
=
""
):
def
__init__
(
self
,
title
,
tags
):
self
.
qtitle
=
qtitle
self
.
title
=
title
self
.
keywords
=
keywords
self
.
tags
=
tags
self
.
description
=
description
self
.
urls
=
[]
def
getApiKey
(
self
):
self
.
session
=
HTMLSession
()
"""
Returns an API key for retrieve json data
def
searchArticles
(
self
):
"""
"""
api_keys
=
[
Search details using google dorks,
"2rk1eg4sexdnp5umrwtwbtwd2insqvgzvejooqrn"
,
With google dorks we can filter out other search results from other web sites.
"yit6ytfcs3ziawdgasfd3bgkbf4tef1m2nzdxvnz"
,
"""
"mpawymyrc6derrwmgodowfsaabtuoes4iiwintd7"
,
html_page
=
requests
.
get
(
]
f
"https://google.com/search?q=site
%3
Amedium.com+{self.qtitle}"
return
random
.
choice
(
api_keys
)
)
def
google
(
self
,
query
):
soup
=
BeautifulSoup
(
html_page
.
content
,
"html.parser"
)
"""
Use a query to search using google search enging
for
link
in
soup
.
findAll
(
"a"
):
"""
if
"https://medium.com"
in
link
[
"href"
]:
search_args
=
(
query
,
1
)
self
.
urls
.
append
(
self
.
extractMediumURLS
(
link
[
"href"
]))
gsearch
=
GoogleSearch
()
self
.
viewArticle
(
self
.
urls
[
0
])
gresults
=
gsearch
.
search
(
*
search_args
)
return
gresults
[
"links"
]
def
extractMediumURLS
(
self
,
uriString
):
"""
def
getValidUrls
(
self
,
links
):
Remove unwanted characters from the url string and filter out the targeted url
"""
"""
Validate and filter out the urls.
uriTrimmed
=
uriString
[
7
:]
Returns the urls that contain medium.com in it as a list
uriTrimmed
=
re
.
match
(
r"^.*?\&sa="
,
uriTrimmed
)
.
group
(
0
)
"""
return
uriTrimmed
.
replace
(
"&sa="
,
""
)
validUrls
=
[]
for
i
in
links
:
def
viewArticle
(
self
,
url
):
if
"medium.com"
in
i
:
html_page
=
self
.
session
.
get
(
url
)
uriTrimmed
=
re
.
match
(
r"^.*?\&sa="
,
i
[
29
:])
.
group
(
0
)
html_page
.
html
.
render
(
timeout
=
20
)
ur
=
uriTrimmed
.
replace
(
"&sa="
,
""
)
validUrls
.
append
(
ur
)
# soup = BeautifulSoup(html_page.content, "html.parser")
return
validUrls
# dom = etree.HTML(str(soup))
with
open
(
"medium.html"
,
"wb"
)
as
med
:
def
getValidSets
(
self
,
validUrls
):
med
.
write
(
html_page
.
content
)
"""
med
.
close
()
Extract usernames and article id's from article url
with
open
(
"medium.html"
,
encoding
=
"utf8"
)
as
sf
:
pass a list of urls => returns objects list that contain usernam and article id
soup
=
BeautifulSoup
(
sf
,
"html.parser"
)
"""
dom
=
etree
.
HTML
(
str
(
soup
))
validSets
=
[]
# art = dom.xpath('//*[@class="a b c"]')[0]
for
url
in
validUrls
:
# print(etree.tostring(art))
try
:
title
=
dom
.
xpath
(
'//*[@class="ap aq ar as at ff av w"]/div/h1'
)[
0
]
.
text
vset
=
{}
article
=
dom
.
xpath
(
'//*[@class="ap aq ar as at ff av w"]'
)[
0
]
print
(
url
)
with
open
(
f
"article-{title.replace(' ','')}.html"
,
"wb"
)
as
artFile
:
username
=
re
.
search
(
r"https://medium.com/([^/?]+)"
,
url
)
.
group
(
1
)
artFile
.
write
(
etree
.
tostring
(
article
))
tag
=
re
.
search
(
r"https://medium.com/([^/?]+)/([^/?]+)"
,
url
)
.
group
(
2
)
artFile
.
close
()
vset
[
"username"
]
=
username
vset
[
"tag"
]
=
tag
validSets
.
append
(
vset
)
except
Exception
as
e
:
print
(
e
)
continue
return
validSets
def
getBlogs
(
self
,
username
,
tag
):
"""
Get the content of the article
"""
blog
=
{}
try
:
response
=
requests
.
get
(
f
"https://api.rss2json.com/v1/api.json?rss_url=https
%3
A
%2
F
%2
Fmedium.com
%2
Ffeed
%2
F{username}&api_key={self.getApiKey()}"
)
if
response
.
status_code
==
200
:
res
=
response
.
json
()
for
item
in
res
[
"items"
]:
if
tag
in
item
[
"link"
]:
blog
=
item
except
Exception
as
e
:
print
(
e
)
return
blog
def
getMediumArticles
(
self
):
"""
return a list of articles and/or resources
"""
links
=
self
.
google
(
f
"site:medium.com {self.title} after:2020-01-01"
)
validUrls
=
self
.
getValidUrls
(
links
)
validSets
=
self
.
getValidSets
(
validUrls
)
blogs
=
[]
for
validset
in
validSets
:
blog
=
self
.
getBlogs
(
validset
[
"username"
],
validset
[
"tag"
])
if
bool
(
blog
):
blogs
.
append
(
blog
)
return
{
"blogs"
:
blogs
,
"resources"
:
validUrls
}
backend/python/auto-answer/requirements.txt
View file @
7963cda7
bson==0.5.10
beautifulsoup4==4.9.3
beautifulsoup4==4.9.3
dnspython==2.1.0
dnspython==2.1.0
lxml==4.6.1
lxml==4.6.1
...
@@ -6,4 +7,5 @@ regex==2020.7.14
...
@@ -6,4 +7,5 @@ regex==2020.7.14
requests==2.24.0
requests==2.24.0
requests-html==0.10.0
requests-html==0.10.0
scipy==1.5.4
scipy==1.5.4
search-engine-parser==0.6.2
youtube-search-python==1.4.6
backend/python/auto-answer/scrapper.py
View file @
7963cda7
from
youtube
import
Youtube
from
youtube
import
Youtube
from
Medium
import
Medium
from
Medium
import
Medium
from
Dev
import
DevTo
from
stof
import
STOF
from
stof
import
STOF
import
sys
import
sys
from
database
import
get_database
from
database
import
get_database
def
saveAnswer
(
ans_id
,
stackoverflow
,
videos
):
def
saveAnswer
(
ans_id
,
stackoverflow
,
videos
,
medium_r
,
dev_r
):
db
=
get_database
()
db
=
get_database
()
try
:
try
:
from
bson.objectid
import
ObjectId
from
bson.objectid
import
ObjectId
...
@@ -13,7 +14,26 @@ def saveAnswer(ans_id, stackoverflow, videos):
...
@@ -13,7 +14,26 @@ def saveAnswer(ans_id, stackoverflow, videos):
automatedanswers
=
db
[
"automatedanswers"
]
automatedanswers
=
db
[
"automatedanswers"
]
automatedanswers
.
update_one
(
automatedanswers
.
update_one
(
{
"_id"
:
ObjectId
(
ans_id
)},
{
"_id"
:
ObjectId
(
ans_id
)},
{
"$set"
:
{
"youtube"
:
videos
,
"stackoverflow"
:
stackoverflow
}},
{
"$set"
:
{
"youtube"
:
videos
,
"stackoverflow"
:
stackoverflow
,
"medium_articles"
:
medium_r
[
"blogs"
],
"dev_articles"
:
dev_r
[
"blogs"
],
"medium_resources"
:
medium_r
[
"resources"
],
"dev_resources"
:
dev_r
[
"resources"
],
}
},
)
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"
],
}
)
)
except
NameError
as
err
:
except
NameError
as
err
:
print
(
err
)
print
(
err
)
...
@@ -23,19 +43,19 @@ if __name__ == "__main__":
...
@@ -23,19 +43,19 @@ if __name__ == "__main__":
# title = input("Enter question title: ")
# title = input("Enter question title: ")
title
=
sys
.
argv
[
1
]
# "python django or flask for web development"
title
=
sys
.
argv
[
1
]
# "python django or flask for web development"
tags
=
sys
.
argv
[
2
]
# ["react"]
tags
=
sys
.
argv
[
2
]
# ["react"]
AUTO_ANS_ID
=
sys
.
argv
[
3
]
# "60d
746076689344694ad9e30" #
AUTO_ANS_ID
=
sys
.
argv
[
3
]
# "60d
c9a5f84692f001569d7ab"
stack
=
STOF
(
title
)
stack
=
STOF
(
title
)
ans
=
stack
.
searchQuestion
()
ans
=
stack
.
searchQuestion
()
print
(
ans
)
print
(
ans
)
# medium = Medium(title
)
medium
=
Medium
(
title
,
tags
)
# medium.search
Articles()
medium_articels
=
medium
.
getMedium
Articles
()
# f = open("data.txt", "a")
# f.write(f"updated {title} {tags} {AUTO_ANS_ID}\n"
)
devto
=
DevTo
(
title
,
tags
)
# f.close
()
dev_articles
=
devto
.
getDevArticles
()
youtube
=
Youtube
(
title
,
tags
)
youtube
=
Youtube
(
title
,
tags
)
videos
=
youtube
.
find_videos
()
videos
=
youtube
.
find_videos
()
saveAnswer
(
AUTO_ANS_ID
,
ans
,
videos
)
saveAnswer
(
AUTO_ANS_ID
,
ans
,
videos
,
medium_articels
,
dev_articles
)
print
(
"WORKED"
)
print
(
"WORKED"
)
sys
.
stdout
.
flush
()
sys
.
stdout
.
flush
()
backend/requirements.txt
View file @
7963cda7
...
@@ -7,4 +7,5 @@ regex==2020.7.14
...
@@ -7,4 +7,5 @@ regex==2020.7.14
requests==2.24.0
requests==2.24.0
requests-html==0.10.0
requests-html==0.10.0
scipy==1.5.4
scipy==1.5.4
search-engine-parser==0.6.2
youtube-search-python==1.4.6
youtube-search-python==1.4.6
client/components/automated-answer/index.js
View file @
7963cda7
import
React
from
'
react
'
import
React
from
'
react
'
import
StackOverflowAnswer
from
'
../stof-answer
'
import
StackOverflowAnswer
from
'
../stof-answer
'
import
YoutubeVideoWrapper
from
'
../youtube-videos/YoutubeVideoWrapper
'
const
AutomatedAnswer
=
({
automatedAnswer
})
=>
{
const
AutomatedAnswer
=
({
automatedAnswer
})
=>
{
console
.
log
(
automatedAnswer
)
console
.
log
(
automatedAnswer
)
...
@@ -10,6 +11,13 @@ const AutomatedAnswer = ({ automatedAnswer }) => {
...
@@ -10,6 +11,13 @@ const AutomatedAnswer = ({ automatedAnswer }) => {
)
:
(
)
:
(
<
h1
>
No
Stack
overflow
<
/h1
>
<
h1
>
No
Stack
overflow
<
/h1
>
)}
)}
{
automatedAnswer
.
youtube
!=
null
&&
automatedAnswer
.
youtube
.
length
>=
1
?
(
<
YoutubeVideoWrapper
videos
=
{
automatedAnswer
.
youtube
}
/
>
)
:
(
<
h1
>
No
youtubes
found
for
this
question
<
/h1
>
)}
<
/
>
<
/
>
)
)
}
}
...
...
client/components/stof-answer/index.js
View file @
7963cda7
...
@@ -7,7 +7,9 @@ const StackOverflowAnswer = ({ stof }) => {
...
@@ -7,7 +7,9 @@ const StackOverflowAnswer = ({ stof }) => {
}
}
return
(
return
(
<>
<>
<
h1
className
=
{
styles
.
h
}
>
Answer
from
Stackoverflow
-
{
stof
.
status
}
<
/h1
>
<
h1
className
=
{
styles
.
h
}
>
I
found
{
stof
.
status
}
answer
on
Stackoverflow
<
/h1
>
<
div
className
=
{
styles
.
wrapper
}
>
<
div
className
=
{
styles
.
wrapper
}
>
<
div
dangerouslySetInnerHTML
=
{
createMarkup
()}
><
/div
>
<
div
dangerouslySetInnerHTML
=
{
createMarkup
()}
><
/div
>
<
/div
>
<
/div
>
...
...
client/components/stof-answer/stof-answer.module.css
View file @
7963cda7
...
@@ -5,8 +5,10 @@
...
@@ -5,8 +5,10 @@
padding
:
0.8em
;
padding
:
0.8em
;
border-radius
:
10px
;
border-radius
:
10px
;
font-family
:
'Open Sans'
,
sans-serif
;
font-family
:
'Open Sans'
,
sans-serif
;
margin-bottom
:
3em
;
color
:
white
;
}
}
.h
{
.h
{
font-size
:
1.3
em
!important
;
font-size
:
2
em
!important
;
}
}
client/components/youtube-videos/YoutubeVideoWrapper.js
0 → 100644
View file @
7963cda7
import
React
from
'
react
'
import
YoutubeVideo
from
'
./youtube-video/YoutubeVideo
'
import
styles
from
'
./YoutubeVideoWrapper.module.css
'
const
YoutubeVideoWrapper
=
({
videos
})
=>
{
return
(
<>
<
h1
className
=
{
styles
.
h1
}
>
Here
are
{
videos
.
length
}
video
{
videos
.
length
>
1
&&
'
s
'
}
I
found
on
youtube
<
/h1
>
<
div
className
=
{
styles
.
wrapper
}
>
{
videos
.
map
((
video
,
index
)
=>
{
return
<
YoutubeVideo
video
=
{
video
}
key
=
{
index
}
/
>
})}
<
/div
>
<
/
>
)
}
export
default
YoutubeVideoWrapper
client/components/youtube-videos/YoutubeVideoWrapper.module.css
0 → 100644
View file @
7963cda7
.wrapper
{
margin-top
:
0.5em
;
background-color
:
#2d2d2d
;
padding
:
0.8em
;
border-radius
:
2px
;
margin-bottom
:
3em
;
}
.h1
{
font-size
:
2em
!important
;
}
client/components/youtube-videos/youtube-video/YoutubeVideo.js
0 → 100644
View file @
7963cda7
import
React
from
'
react
'
import
styles
from
'
./YoutubeVideo.module.css
'
const
YoutubeVideo
=
({
video
})
=>
{
console
.
log
(
video
.
substring
(
32
,
video
.
length
-
1
))
return
(
<
div
className
=
{
styles
.
video_responsive
}
>
<
iframe
width
=
"
853
"
height
=
"
480
"
src
=
{
`https://youtube.com/embed/
${
video
.
substring
(
32
,
video
.
length
)}
`
}
frameBorder
=
"
0
"
allow
=
"
accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture
"
allowFullScreen
title
=
"
Embedded youtube
"
/>
<
/div
>
)
}
export
default
YoutubeVideo
client/components/youtube-videos/youtube-video/YoutubeVideo.module.css
0 → 100644
View file @
7963cda7
.video_responsive
{
overflow
:
hidden
;
padding-bottom
:
56.25%
;
position
:
relative
;
height
:
0
;
margin
:
1em
0
;
iframe
{
left
:
0
;
top
:
0
;
height
:
100%
;
width
:
100%
;
position
:
absolute
;
}
}
client/styles/automatedanswer.css
View file @
7963cda7
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
line-height
:
1.5em
;
line-height
:
1.5em
;
word-break
:
break-word
;
word-break
:
break-word
;
font-size
:
15px
;
font-size
:
15px
;
color
:
white
;
a
{
a
{
text-decoration
:
underline
;
text-decoration
:
underline
;
color
:
var
(
--blue-300
);
color
:
var
(
--blue-300
);
...
@@ -43,6 +43,13 @@
...
@@ -43,6 +43,13 @@
margin-top
:
0.6em
;
margin-top
:
0.6em
;
}
}
}
}
h2
{
color
:
white
!important
;
font-weight
:
bold
!important
;
font-size
:
1.4em
!important
;
margin
:
1.6em
0
0.7em
0
;
}
}
}
.s-prose
*
:not
(
.s-code-block
)
>
code
{
.s-prose
*
:not
(
.s-code-block
)
>
code
{
...
@@ -65,3 +72,40 @@ sup {
...
@@ -65,3 +72,40 @@ sup {
sub
{
sub
{
vertical-align
:
sub
;
vertical-align
:
sub
;
}
}
.s-table-container
{
/* margin-bottom: 1.1em; */
overflow-x
:
auto
;
}
.s-table
{
display
:
table
;
width
:
100%
;
max-width
:
100%
;
border-collapse
:
collapse
;
border-spacing
:
0
;
font-size
:
13px
;
}
.s-table
thead
th
{
vertical-align
:
bottom
;
white-space
:
nowrap
;
background-color
:
var
(
--black-600
);
line-height
:
1.15384615
;
}
.s-table
th
{
font-weight
:
bold
;
color
:
var
(
--fc-dark
);
}
.s-table
th
,
.s-table
td
{
padding
:
8px
;
border-top
:
1px
solid
var
(
--black-100
);
border-left
:
1px
solid
var
(
--black-100
);
border-right
:
1px
solid
var
(
--black-100
);
vertical-align
:
middle
;
color
:
var
(
--fc-medium
);
text-align
:
left
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment