Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
INB
eTRANSAFE
pretox-app
Commits
b51c29be
Commit
b51c29be
authored
Oct 08, 2021
by
jcorvi
Browse files
Merge branch 'develop' into 'master'
Develop See merge request
!4
parents
1a60626b
709bf528
Pipeline
#25036
passed with stage
in 1 minute and 55 seconds
Changes
15
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
.gitlab-ci.yml
View file @
b51c29be
variables
:
DOCKER_
USER
:
javicorvi
DOCKER_BUILD
:
$DOCKER_
USER
/$CI_PROJECT_
NAME
:$CI_COMMIT_REF_NAME
DOCKER_
REGISTRY
:
registry.gitlab.bsc.es
IMAGE_FULL_PATH
:
$DOCKER_
REGISTRY
/$CI_PROJECT_
PATH
:$CI_COMMIT_REF_NAME
stages
:
-
build
build_docker_image
:
stage
:
build
script
:
-
docker login -u
javicorvi -p $DOCKER_PASS
-
docker build -t $
DOCKER_BUILD . -f DockerfileDev
-
docker push $
DOCKER_BUILD
-
docker login -u
gitlab-ci-token -p $CI_BUILD_TOKEN $DOCKER_REGISTRY
-
docker build -t $
IMAGE_FULL_PATH .
-
docker push $
IMAGE_FULL_PATH
tags
:
-
build
src/app/app-routing.module.ts
View file @
b51c29be
...
...
@@ -8,15 +8,11 @@ import { SrdomaintemplateTabulatorComponent } from './srdomaintemplate-tabulator
import
{
PretoxsentencesTabulatorComponent
}
from
'
./pretoxsentences-tabulator/pretoxsentences-tabulator.component
'
;
import
{
FindingTabulatorComponent
}
from
'
./finding-tabulator/finding-tabulator.component
'
;
import
{
LoginComponent
}
from
'
./login/login.component
'
;
import
{
AuthGuard
}
from
'
./authguard.service
'
;
const
routes
:
Routes
=
[
{
path
:
'
login
'
,
component
:
LoginComponent
},
{
path
:
''
,
redirectTo
:
'
/documents
'
,
pathMatch
:
'
full
'
},
// { path: 'find/:id/first', component: SrdomainLevelComponent },
// { path: 'find/:id/second', component: SrdomainLevelComponent },
// { path: 'find/:id/third', component: SrdomainLevelComponent },
//{ path: '', redirectTo: '/documents', pathMatch: 'full' },
{
path
:
''
,
redirectTo
:
'
documents
'
,
pathMatch
:
'
full
'
},
{
path
:
'
find/:id
'
,
component
:
DocumentDetailComponent
,
children
:
[
...
...
@@ -27,15 +23,11 @@ const routes: Routes = [
]
},
{
path
:
'
documents
'
,
component
:
DocumentsComponent
},
{
path
:
'
documents
'
,
component
:
DocumentsComponent
,
canActivate
:
[
AuthGuard
]},
{
path
:
'
first_1
'
,
component
:
SrdomainLevelComponent
},
{
path
:
'
second_2
'
,
component
:
SrdomainLevelComponent
},
{
path
:
'
third_3
'
,
component
:
SrdomainLevelComponent
},
{
path
:
'
third_3
'
,
component
:
SrdomainLevelComponent
}
];
...
...
src/app/app.component.ts
View file @
b51c29be
import
{
Component
}
from
'
@angular/core
'
;
import
{
MatToolbarModule
}
from
'
@angular/material/toolbar
'
;
import
{
Router
}
from
'
@angular/router
'
;
@
Component
({
selector
:
'
app-root
'
,
...
...
src/app/app.module.ts
View file @
b51c29be
import
{
BrowserModule
}
from
'
@angular/platform-browser
'
;
import
{
NgModule
}
from
'
@angular/core
'
;
import
{
HttpClientModule
}
from
'
@angular/common/http
'
;
import
{
HttpClientModule
,
HTTP_INTERCEPTORS
}
from
'
@angular/common/http
'
;
import
{
AppRoutingModule
}
from
'
./app-routing.module
'
;
import
{
AppComponent
}
from
'
./app.component
'
;
import
{
MenuComponent
}
from
'
./menu/menu.component
'
;
...
...
@@ -17,7 +17,7 @@ import { HttpModule } from '@angular/http';
import
{
CookieService
}
from
'
ngx-cookie-service
'
;
import
{
PretoxsentencesTabulatorComponent
}
from
'
./pretoxsentences-tabulator/pretoxsentences-tabulator.component
'
;
import
{
SrdomaintemplateTabulatorComponent
}
from
'
./srdomaintemplate-tabulator/srdomaintemplate-tabulator.component
'
;
import
{
HttpInterceptorService
}
from
'
./httpInterceptor.service
'
;
import
{
MatToolbarModule
}
from
'
@angular/material/toolbar
'
;
import
{
MatTabsModule
}
from
'
@angular/material/tabs
'
;
import
{
BrowserAnimationsModule
}
from
'
@angular/platform-browser/animations
'
;
...
...
@@ -48,7 +48,11 @@ import { SrdomainLevelComponent } from './srdomain-level/srdomain-level.componen
BrowserAnimationsModule
,
MatToolbarModule
],
providers
:
[
LoginService
,
CookieService
],
providers
:
[
LoginService
,
CookieService
,
{
provide
:
HTTP_INTERCEPTORS
,
useClass
:
HttpInterceptorService
,
multi
:
true
}],
bootstrap
:
[
AppComponent
],
exports
:
[
HeaderComponent
,
FooterComponent
,
DocumentsComponent
,
DocumentDetailComponent
,
MessagesComponent
]
})
...
...
src/app/authguard.service.ts
0 → 100644
View file @
b51c29be
import
{
Injectable
}
from
'
@angular/core
'
;
import
{
Router
,
CanActivate
,
ActivatedRouteSnapshot
,
RouterStateSnapshot
}
from
'
@angular/router
'
;
import
{
LoginService
}
from
'
./login.service
'
;
@
Injectable
({
providedIn
:
'
root
'
})
export
class
AuthGuard
implements
CanActivate
{
constructor
(
private
authService
:
LoginService
,
private
router
:
Router
)
{}
canActivate
(
next
:
ActivatedRouteSnapshot
,
state
:
RouterStateSnapshot
)
{
let
loged_in
=
this
.
authService
.
isUserLoggedIn
();
//alert(loged_in);
if
(
!
loged_in
)
{
//alert(1);
this
.
router
.
navigateByUrl
(
'
/login
'
);
return
false
;
}
else
{
//alert(2);
return
true
;
}
}
}
\ No newline at end of file
src/app/document-detail/document-detail.component.html
View file @
b51c29be
<div
class=
"w3-container"
>
<nav
class=
"navbar navbar-expand-lg navbar-dark bg-dark"
>
<a
class=
"navbar-brand"
routerLink=
""
>
Home
</a>
<a
class=
"fa fa-angle-left"
title=
'Previous Document'
routerLink=
""
style=
"color:white;padding: 10px 30px;text-decoration:none;"
aria-hidden=
"true"
tooltip=
'Previous Document'
></a>
<a
class=
"fa fa-angle-right"
title=
'Next Document'
routerLink=
""
style=
"color:white;padding: 10px 30px;text-decoration:none;"
aria-hidden=
"true"
tooltip=
'Next Document'
></a>
<!--
<a class="fa fa-angle-left" title='Previous Document' routerLink="" style="color:white;padding: 10px 30px;text-decoration:none;" aria-hidden="true" tooltip='Previous Document'></a>
<a class="fa fa-angle-right" title='Next Document' routerLink="" style="color:white;padding: 10px 30px;text-decoration:none;" aria-hidden="true" tooltip='Next Document'></a>
-->
</nav>
<div
*ngIf=
"document"
class=
"documentName"
>
<div
class=
"card"
>
...
...
src/app/document-detail/document-detail.component.ts
View file @
b51c29be
...
...
@@ -367,7 +367,7 @@ export class DocumentDetailComponent implements OnInit {
setExportSRDomain
(
data
)
{
const
id
=
+
this
.
route
.
snapshot
.
paramMap
.
get
(
'
id
'
);
//alert(data
.id
);
//alert(data);
//alert(data.export);
this
.
documentService
.
setExportSRDomain
(
id
,
data
.
srDomainId
,
data
.
export
)
.
subscribe
(
text
=>
{
...
...
src/app/document.service.ts
View file @
b51c29be
...
...
@@ -16,11 +16,14 @@ const httpOptions = {
providedIn
:
'
root
'
})
export
class
DocumentService
{
private
documentsUrl
=
environment
.
apiUrl
;
// URL to web api
private
documentsUrl
=
environment
.
apiUrl
+
"
/documents/
"
;
//private documentsUrl = 'http://10.32.6.2:8090/documents/'; // URL to web api
constructor
(
private
http
:
HttpClient
,
private
messageService
:
MessageService
)
{
}
getDocuments
():
Observable
<
Document
[]
>
{
//const headers = new HttpHeaders ({ Authorization: 'Basic '+ btoa('javi'+':'+'pass2')});
return
this
.
http
.
get
<
Document
[]
>
(
this
.
documentsUrl
).
pipe
(
tap
(
_
=>
this
.
log
(
'
fetched documents
'
)),
catchError
(
this
.
handleError
<
Document
[]
>
(
'
getDocuments
'
,
[]))
...
...
@@ -36,7 +39,7 @@ export class DocumentService {
/** GET document by id. Will 404 if id not found */
getDocument
(
id
:
number
):
Observable
<
Document
>
{
const
url
=
`
${
this
.
documentsUrl
}
/
${
id
}
`
;
const
url
=
`
${
this
.
documentsUrl
}${
id
}
`
;
return
this
.
http
.
get
<
Document
>
(
url
).
pipe
(
tap
(
_
=>
this
.
log
(
`fetched document id=
${
id
}
`
)),
catchError
(
this
.
handleError
<
Document
>
(
`getDocument id=
${
id
}
`
))
...
...
@@ -45,7 +48,7 @@ export class DocumentService {
/** GET document by id. Will 404 if id not found */
exportDocument
(
id
:
number
):
any
{
const
url
=
`
${
this
.
documentsUrl
}
/
export/
${
id
}
`
;
const
url
=
`
${
this
.
documentsUrl
}
export/
${
id
}
`
;
return
this
.
http
.
get
(
url
,
{
responseType
:
'
blob
'
,
})
...
...
@@ -89,7 +92,7 @@ export class DocumentService {
/** GET Snipped of finding selected */
findingSelected
(
id
:
number
,
finding
:
Finding
):
Observable
<
string
>
{
const
url
=
`
${
this
.
documentsUrl
}
/
${
id
}
/finding/
${
finding
.
findingId
}
`
;
const
url
=
`
${
this
.
documentsUrl
}${
id
}
/finding/
${
finding
.
findingId
}
`
;
return
this
.
http
.
get
(
url
,
{
responseType
:
'
text
'
}).
pipe
(
tap
(
_
=>
this
.
log
(
`fetched finding id=
${
finding
.
findingId
}
`
)),
catchError
(
this
.
handleError
<
string
>
(
`getFinding id=
${
finding
.
findingId
}
`
))
...
...
@@ -99,7 +102,7 @@ export class DocumentService {
/** GET Snipped of findings selected just in case is needed, is not complete only the calls againt rest api is done*/
findingsSelected
(
id
:
number
,
finding
:
Finding
):
Observable
<
string
>
{
//const url = `${this.documentsUrl}/${id}/finding/${finding.findingId}`;
const
url
=
`
${
this
.
documentsUrl
}
/
${
id
}
/findings/1,2`
;
const
url
=
`
${
this
.
documentsUrl
}${
id
}
/findings/1,2`
;
return
this
.
http
.
get
(
url
,
{
responseType
:
'
text
'
}).
pipe
(
tap
(
_
=>
this
.
log
(
`fetched finding id=
${
finding
.
findingId
}
`
)),
catchError
(
this
.
handleError
<
string
>
(
`getFinding id=
${
finding
.
findingId
}
`
))
...
...
@@ -108,7 +111,7 @@ export class DocumentService {
/** GET Snipped of all finding evidence */
getAllEvidence
(
id
:
number
):
Observable
<
string
>
{
const
url
=
`
${
this
.
documentsUrl
}
/
${
id
}
/evidence/all`
;
const
url
=
`
${
this
.
documentsUrl
}${
id
}
/evidence/all`
;
return
this
.
http
.
get
(
url
,
{
responseType
:
'
text
'
}).
pipe
(
tap
(
_
=>
this
.
log
(
`fetched all evidence id=
${
id
}
`
)),
catchError
(
this
.
handleError
<
string
>
(
`getFindings id=
${
id
}
`
))
...
...
@@ -117,7 +120,7 @@ export class DocumentService {
pretoxSentenceSelected
(
id
:
number
,
pretoxSentence
:
Annotation
):
Observable
<
string
>
{
const
url
=
`
${
this
.
documentsUrl
}
/
${
id
}
/sentence/
${
pretoxSentence
.
id
}
`
;
const
url
=
`
${
this
.
documentsUrl
}${
id
}
/sentence/
${
pretoxSentence
.
id
}
`
;
//const url = `${this.documentsUrl}/${id}/sentence/1`;
return
this
.
http
.
get
(
url
,
{
responseType
:
'
text
'
}).
pipe
(
tap
(
_
=>
this
.
log
(
`fetched pretox sentence id=
${
pretoxSentence
.
id
}
`
)),
...
...
@@ -144,7 +147,7 @@ export class DocumentService {
/** DELETE: delete the document from the server */
deleteDocument
(
document
:
Document
|
number
):
Observable
<
Document
>
{
const
id
=
typeof
document
===
'
number
'
?
document
:
document
.
documentId
;
const
url
=
`
${
this
.
documentsUrl
}
/
${
id
}
`
;
const
url
=
`
${
this
.
documentsUrl
}${
id
}
`
;
return
this
.
http
.
delete
<
Document
>
(
url
,
httpOptions
).
pipe
(
tap
(
_
=>
this
.
log
(
`deleted document id=
${
id
}
`
)),
...
...
src/app/httpInterceptor.service.ts
0 → 100644
View file @
b51c29be
import
{
HttpInterceptor
,
HttpRequest
,
HttpHandler
,
HttpEvent
,
HttpHeaders
}
from
'
@angular/common/http
'
;
import
{
Injectable
}
from
'
@angular/core
'
;
import
{
Observable
}
from
'
rxjs
'
;
import
{
LoginService
}
from
'
./login.service
'
;
@
Injectable
()
export
class
HttpInterceptorService
implements
HttpInterceptor
{
constructor
(
private
authenticationService
:
LoginService
)
{
}
intercept
(
req
:
HttpRequest
<
any
>
,
next
:
HttpHandler
):
Observable
<
HttpEvent
<
any
>>
{
if
(
this
.
authenticationService
.
isUserLoggedIn
()
&&
req
.
url
.
indexOf
(
'
basicauth
'
)
===
-
1
)
{
const
authReq
=
req
.
clone
({
headers
:
new
HttpHeaders
({
'
Content-Type
'
:
'
application/json
'
,
'
Authorization
'
:
sessionStorage
.
getItem
(
'
tokenUser
'
)
//'Authorization': `Basic ${window.btoa(this.authenticationService.username + ":" + this.authenticationService.password)}`
})
});
return
next
.
handle
(
authReq
);
}
else
{
return
next
.
handle
(
req
);
}
}
}
\ No newline at end of file
src/app/login.service.ts
View file @
b51c29be
import
{
Injectable
}
from
'
@angular/co
re
'
;
import
{
Router
}
from
'
@angular/
router
'
;
import
{
Http
,
RequestOptions
,
Headers
}
from
'
@angular/http
'
;
import
{
map
}
from
'
rxjs/operators
'
;
import
{
CookieService
}
from
'
ngx-cookie-service
'
;
@
Injectable
(
)
import
{
HttpClient
}
from
'
@angular/co
mmon/http
'
;
import
{
Injectable
}
from
'
@angular/
core
'
;
import
{
map
}
from
'
rxjs/operators
'
;
import
{
environment
}
from
'
./../environments/environment
'
;
@
Injectable
({
providedIn
:
'
root
'
}
)
export
class
LoginService
{
constructor
(
private
router
:
Router
,
private
http
:
Http
,
private
cookieService
:
CookieService
)
{}
obtainAccessToken
(
loginData
)
{
const
params
=
new
URLSearchParams
();
params
.
append
(
'
username
'
,
loginData
.
username
);
params
.
append
(
'
password
'
,
loginData
.
password
);
params
.
append
(
'
grant_type
'
,
'
password
'
);
params
.
append
(
'
client_id
'
,
'
R2dpxQ3vPrtfgF72
'
);
const
headers
=
new
Headers
({
'
Content-type
'
:
'
application/x-www-form-urlencoded; charset=utf-8
'
,
'
Authorization
'
:
'
Basic
'
+
btoa
(
'
R2dpxQ3vPrtfgF72:fDw7Mpkk5czHNuSRtmhGmAGL42CaxQB9
'
)});
let
options
=
new
RequestOptions
({
headers
:
headers
});
this
.
http
.
post
(
'
http://localhost:8085/auth/login
'
,
params
.
toString
(),
options
).
pipe
(
map
(
data
=>
{}))
.
subscribe
(
data
=>
this
.
saveToken
(
data
),
err
=>
alert
(
'
Invalid Credentials
'
));
private
apiUrl
=
environment
.
apiUrl
;
USER_NAME_SESSION_ATTRIBUTE_NAME
=
'
authenticatedUser
'
;
USER_BASIC_TOKEN_ATTRIBUTE_NAME
=
'
tokenUser
'
;
public
username
:
String
;
public
password
:
String
;
constructor
(
private
http
:
HttpClient
)
{
}
saveToken
(
token
)
{
const
expireDate
=
new
Date
().
getTime
()
+
(
1000
*
token
.
expires_in
);
this
.
cookieService
.
set
(
'
access_token
'
,
token
.
access_token
,
expireDate
);
this
.
router
.
navigate
([
'
/
'
]);
authenticationService
(
username
:
String
,
password
:
String
)
{
const
url
=
`
${
this
.
apiUrl
}
/basicauth`
;
return
this
.
http
.
get
(
url
,
{
headers
:
{
authorization
:
this
.
createBasicAuthToken
(
username
,
password
)
}
}).
pipe
(
map
((
res
)
=>
{
this
.
username
=
username
;
this
.
password
=
password
;
this
.
registerSuccessfulLogin
(
username
,
password
);
}));
}
createBasicAuthToken
(
username
:
String
,
password
:
String
)
{
return
'
Basic
'
+
window
.
btoa
(
username
+
"
:
"
+
password
)
}
checkCredentials
()
{
if
(
!
this
.
cookieService
.
check
(
'
access_token
'
))
{
this
.
router
.
navigate
([
'
/login
'
]);
}
registerSuccessfulLogin
(
username
,
password
)
{
sessionStorage
.
setItem
(
this
.
USER_NAME_SESSION_ATTRIBUTE_NAME
,
username
);
sessionStorage
.
setItem
(
this
.
USER_BASIC_TOKEN_ATTRIBUTE_NAME
,
this
.
createBasicAuthToken
(
username
,
password
));
}
logout
()
{
this
.
cookieService
.
delete
(
'
access_token
'
);
this
.
router
.
navigate
([
'
/login
'
]);
sessionStorage
.
removeItem
(
this
.
USER_NAME_SESSION_ATTRIBUTE_NAME
);
this
.
username
=
null
;
this
.
password
=
null
;
}
isUserLoggedIn
()
{
let
user
=
sessionStorage
.
getItem
(
this
.
USER_NAME_SESSION_ATTRIBUTE_NAME
);
if
(
user
===
null
)
return
false
;
return
true
;
}
getLoggedInUserName
()
{
let
user
=
sessionStorage
.
getItem
(
this
.
USER_NAME_SESSION_ATTRIBUTE_NAME
);
if
(
user
===
null
)
return
''
;
return
user
;
}
}
}
\ No newline at end of file
src/app/login/login.component.css
View file @
b51c29be
/* BASIC */
html
{
background-color
:
#56baed
;
}
body
{
font-family
:
"Poppins"
,
sans-serif
;
height
:
100vh
;
}
a
{
cursor
:
default
;
color
:
#92badd
;
display
:
inline-block
;
text-decoration
:
none
;
font-weight
:
400
;
}
h2
{
text-align
:
center
;
font-size
:
16px
;
font-weight
:
600
;
display
:
inline-block
;
margin
:
40px
8px
10px
8px
;
color
:
#cccccc
;
}
/* STRUCTURE */
.wrapper
{
display
:
flex
;
align-items
:
center
;
flex-direction
:
column
;
justify-content
:
center
;
width
:
100%
;
min-height
:
100%
;
padding
:
200px
;
}
#formContent
{
-webkit-border-radius
:
10px
10px
10px
10px
;
border-radius
:
10px
10px
10px
10px
;
background
:
#fff
;
padding
:
30px
;
width
:
90%
;
max-width
:
450px
;
position
:
relative
;
padding
:
0px
;
-webkit-box-shadow
:
0
30px
60px
0
rgba
(
0
,
0
,
0
,
0.3
);
box-shadow
:
0
30px
60px
0
rgba
(
0
,
0
,
0
,
0.3
);
text-align
:
center
;
}
#formFooter
{
background-color
:
#f6f6f6
;
border-top
:
1px
solid
#dce8f1
;
padding
:
25px
;
text-align
:
center
;
-webkit-border-radius
:
0
0
10px
10px
;
border-radius
:
0
0
10px
10px
;
}
/* TABS */
h2
.inactive
{
color
:
#cccccc
;
}
h2
.active
{
color
:
#0d0d0d
;
border-bottom
:
2px
solid
#5fbae9
;
}
/* FORM TYPOGRAPHY*/
input
[
type
=
button
],
input
[
type
=
submit
],
input
[
type
=
reset
]
{
background-color
:
#56baed
;
border
:
none
;
color
:
white
;
padding
:
15px
80px
;
text-align
:
center
;
text-decoration
:
none
;
display
:
inline-block
;
text-transform
:
uppercase
;
font-size
:
13px
;
-webkit-box-shadow
:
0
10px
30px
0
rgba
(
95
,
186
,
233
,
0.4
);
box-shadow
:
0
10px
30px
0
rgba
(
95
,
186
,
233
,
0.4
);
-webkit-border-radius
:
5px
5px
5px
5px
;
border-radius
:
5px
5px
5px
5px
;
margin
:
5px
20px
40px
20px
;
-webkit-transition
:
all
0.3s
ease-in-out
;
-moz-transition
:
all
0.3s
ease-in-out
;
-ms-transition
:
all
0.3s
ease-in-out
;
-o-transition
:
all
0.3s
ease-in-out
;
transition
:
all
0.3s
ease-in-out
;
}
input
[
type
=
button
]
:hover
,
input
[
type
=
submit
]
:hover
,
input
[
type
=
reset
]
:hover
{
background-color
:
#39ace7
;
}
input
[
type
=
button
]
:active
,
input
[
type
=
submit
]
:active
,
input
[
type
=
reset
]
:active
{
-moz-transform
:
scale
(
0.95
);
-webkit-transform
:
scale
(
0.95
);
-o-transform
:
scale
(
0.95
);
-ms-transform
:
scale
(
0.95
);
transform
:
scale
(
0.95
);
}
input
[
type
=
text
],
[
type
=
password
]
{
background-color
:
#f6f6f6
;
border
:
none
;
color
:
#0d0d0d
;
padding
:
15px
32px
;
text-align
:
center
;
text-decoration
:
none
;
display
:
inline-block
;
font-size
:
16px
;
margin
:
5px
;
width
:
85%
;
border
:
2px
solid
#f6f6f6
;
-webkit-transition
:
all
0.5s
ease-in-out
;
-moz-transition
:
all
0.5s
ease-in-out
;
-ms-transition
:
all
0.5s
ease-in-out
;
-o-transition
:
all
0.5s
ease-in-out
;
transition
:
all
0.5s
ease-in-out
;
-webkit-border-radius
:
5px
5px
5px
5px
;
border-radius
:
5px
5px
5px
5px
;
}
input
[
type
=
text
]
:focus
{
background-color
:
#fff
;
border-bottom
:
2px
solid
#5fbae9
;
}
input
[
type
=
text
]
:placeholder
{
color
:
#cccccc
;
}
/* ANIMATIONS */
/* Simple CSS3 Fade-in-down Animation */
.fadeInDown
{
-webkit-animation-name
:
fadeInDown
;
animation-name
:
fadeInDown
;
-webkit-animation-duration
:
1s
;
animation-duration
:
1s
;
-webkit-animation-fill-mode
:
both
;
animation-fill-mode
:
both
;
}
@-webkit-keyframes
fadeInDown
{
0
%
{
opacity
:
0
;
-webkit-transform
:
translate3d
(
0
,
-100%
,
0
);
transform
:
translate3d
(
0
,
-100%
,
0
);
}
100
%
{
opacity
:
1
;
-webkit-transform
:
none
;
transform
:
none
;
}
}
@keyframes
fadeInDown
{
0
%
{
opacity
:
0
;
-webkit-transform
:
translate3d
(
0
,
-100%
,
0
);
transform
:
translate3d
(
0
,
-100%
,
0
);
}
100
%
{
opacity
:
1
;
-webkit-transform
:
none
;
transform
:
none
;
}
}
/* Simple CSS3 Fade-in Animation */
@-webkit-keyframes
fadeIn
{
from
{
opacity
:
0
;
}
to
{
opacity
:
1
;
}
}
@-moz-keyframes
fadeIn
{
from
{
opacity
:
0
;
}
to
{
opacity
:
1
;
}
}
@keyframes
fadeIn
{
from
{
opacity
:
0
;
}
to
{
opacity
:
1
;
}
}
.fadeIn
{
opacity
:
0
;
-webkit-animation
:
fadeIn
ease-in
1
;
-moz-animation
:
fadeIn
ease-in
1
;
animation
:
fadeIn
ease-in
1
;
-webkit-animation-fill-mode
:
forwards
;
-moz-animation-fill-mode
:
forwards
;
animation-fill-mode
:
forwards
;
-webkit-animation-duration
:
1s
;
-moz-animation-duration
:
1s
;
animation-duration
:
1s
;
}
.fadeIn.first
{
-webkit-animation-delay
:
0.4s
;
-moz-animation-delay
:
0.4s
;
animation-delay
:
0.4s
;
}
.fadeIn.second
{
-webkit-animation-delay
:
0.6s
;
-moz-animation-delay
:
0.6s
;
animation-delay
:
0.6s
;
}
.fadeIn.third
{
-webkit-animation-delay
:
0.8s
;
-moz-animation-delay
:
0.8s
;
animation-delay
:
0.8s
;
}
.fadeIn.fourth
{
-webkit-animation-delay
:
1s
;
-moz-animation-delay
:
1s
;
animation-delay
:
1s
;
}
/* Simple CSS3 Fade-in Animation */
.underlineHover
:after
{
display
:
block
;
left
:
0
;
bottom
:
-10px
;
width
:
0
;
height
:
2px
;
background-color
:
#56baed
;
content
:
""
;
transition
:
width
0.2s
;
}
.underlineHover
:hover
{
color
:
#0d0d0d
;
}
.underlineHover
:hover:after
{
width
:
100%
;
}
/* OTHERS */
*
:focus
{
outline
:
none
;
}
#icon
{
<