summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/common/activeLink.component.js16
-rw-r--r--client/common/common.css348
-rw-r--r--client/common/footer.component.js10
-rw-r--r--client/common/index.js11
-rw-r--r--client/common/keyframe.component.js118
-rw-r--r--client/common/keyframes.component.js95
-rw-r--r--client/common/loader.component.js5
-rw-r--r--client/common/sidebar.component.js21
-rw-r--r--client/faceSearch/faceSearch.query.js23
9 files changed, 25 insertions, 622 deletions
diff --git a/client/common/activeLink.component.js b/client/common/activeLink.component.js
deleted file mode 100644
index 59f63881..00000000
--- a/client/common/activeLink.component.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from 'react'
-import { NavLink } from 'react-router-dom'
-
-export default function ActiveLink({
- to,
- className = 'navlink',
- children
-}) {
- return (
- <span className={className}>
- <NavLink to={to}>
- {children}
- </NavLink>
- </span>
- )
-}
diff --git a/client/common/common.css b/client/common/common.css
index 4b939df0..56cf2fe9 100644
--- a/client/common/common.css
+++ b/client/common/common.css
@@ -1,347 +1 @@
-/* css boilerplate */
-
-* { box-sizing: border-box; }
-html,body {
- margin: 0; padding: 0;
- width: 100%; height: 100%;
-}
-body {
- font-family: Helvetica, sans-serif;
- font-weight: 300;
-}
-
-h1 {
-
-}
-h2 {
- font-weight: normal;
- margin: 10px 0;
- padding: 3px;
- font-size: 24px;
-}
-h3 {
- font-weight: normal;
- margin: 10px 0 0 0;
- padding: 3px;
- font-size: 18px;
-}
-h4 {
- font-weight: 300;
- font-size: 12px;
- letter-spacing: 2px;
- color: #888;
- text-transform: uppercase;
- margin: 5px 10px;
- margin-top: 20px;
-}
-h4:first-child {
- margin-top: 10px;
-}
-
-.app {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: row;
- align-items: flex-start;
- justify-content: flex-start;
-}
-
-/* header stuff */
-
-header {
- width: 100%;
- background: #11f;
- color: white;
- align-items: stretch;
- display: flex;
- flex-wrap: wrap;
- justify-content: space-between;
- z-index: 3;
-}
-header > section {
- justify-content: flex-start;
- align-items: center;
- display: flex;
- flex: 1 0;
- font-weight: bold;
-}
-header > section:last-of-type {
- justify-content: flex-end;
-}
-
-/* sidebar / body columns */
-
-.sidebar {
- display: flex;
- flex-direction: column;
- justify-content: flex-start;
- align-items: flex-start;
- height: 100%;
- float: left;
- width: 200px;
- flex: 0 0 200px;
- padding: 10px;
- margin-right: 10px;
-}
-.sidebar a {
- display: block;
- padding: 10px 10px;
- text-decoration: none;
- color: #444;
-}
-.sidebar a.active {
- font-weight: bold;
- color: #222;
-}
-.body {
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- justify-content: flex-start;
- flex-grow: 1;
-}
-.body > div {
- padding-bottom: 40px;
-}
-
-/* buttons / forms */
-
-.btn:focus, .btn:hover {
- background: #f1f1fc;
- color: #4b48d6 !important;
- text-decoration: none;
-}
-.btn {
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
- background: #fff;
- border: .05rem solid;
- border-radius: 2px;
- margin-right: 5px;
- color: #11f;
- cursor: pointer;
- display: inline-block;
- font-size: .8rem;
- height: 1.8rem;
- line-height: 1rem;
- outline: none;
- padding: .35rem .4rem;
- text-align: center;
- text-decoration: none;
- -webkit-transition: all .2s ease;
- -o-transition: all .2s ease;
- transition: all .2s ease;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- vertical-align: middle;
- white-space: nowrap;
-}
-.btn.reset,
-.btn.panic {
- color: #b00;
-}
-.btn.btn-primary {
- background: #11f;
- border-color: #11f;
- color: white;
-}
-.btn[disabled] {
- color: #bbb !important;
- border-color: #bbb !important;
- background: white !important;
- cursor: default;
-}
-.btn.btn-primary:focus,
-.btn.btn-primary:hover {
- background: #0808ee;
- color: white !important;
-}
-.row .btn {
- margin: 0 5px 0 0;
-}
-input[type=text] {
- border: 1px solid #888;
- padding: 4px;
- font-size: 15px;
-}
-
-
-/* tables on metadata pages */
-
-table {
- border: 0;
- margin: 0;
- padding: 0;
- border-spacing: 0;
-}
-.tableObject td,
-.tableObject th {
- padding: 3px;
- vertical-align: top;
-}
-.tableObject hr {
- width: 100%;
- color: transparent;
- border: 0;
- border-bottom: 1px solid #bbb;
- align: left;
- margin: 3px 0;
- padding: 0;
-}
-.tableObject th,
-.tableTuples th {
- min-width: 145px;
- text-align: left;
- text-transform: capitalize;
- padding: 3px;
- padding-right: 10px;
- font-weight: 300;
- color: #333;
-}
-.tableTuples td {
- text-align: right;
- padding: 3px;
-}
-.tableObject td {
- font-weight: normal;
- color: #000;
-}
-.tableObject .tableObject {
- border: 1px solid #ddd;
-}
-.tableArray {
- border: 1px solid #ddd;
- border-spacing: 0;
-}
-.tableArray td {
- border-bottom: 1px solid #ddd;
-}
-.gray {
- font-size: 12px;
- color: #888;
- display: block;
-}
-.sha256.heading {
- margin: 20px 0 0px;
-}
-.gray span {
- padding-right: 5px;
-}
-.gray {
- margin-bottom: 10px;
-}
-.gray a {
- color: #666;
-}
-
-.verified {
- color: #080;
- font-weight: bold;
-}
-.unverified {
- color: #f00;
- font-weight: 300;
-}
-
-.loading, .error {
- font-weight: normal;
- margin: 10px 0;
- padding: 3px;
- font-size: 24px;
-}
-
-.title {
- text-transform: capitalize;
-}
-.rect {
- position: absolute;
-}
-.rect { border: 1px solid rgba(0,0,255); background-color: rgba(0,0,255,0.1); }
-
-/* videos / video preloader */
-
-video {
- max-width: 640px;
- margin: 10px 0;
-}
-.video {
- margin: 0 0 10px 0;
-}
-.video .bg {
- cursor: pointer;
- position: relative;
- background-size: cover;
-}
-.video .play {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate3d(-50%, -50%, 0);
- width: 20%;
- height: 20%;
- background-image: url(/search/static/img/play.png);
- background-position: center center;
- background-size: contain;
- background-repeat: no-repeat;
-}
-.desktop .video .play:hover {
- -webkit-filter: invert(60%) sepia(100%) saturate(500%) hue-rotate(160deg);
-}
-
-/* spectre.css loader */
-
-.loaderWrapper {
- display: inline-block;
- position: relative;
- width: .8rem;
- height: .8rem;
- padding: 10px;
-}
-.loader {
- color: transparent !important;
- min-height: .8rem;
- pointer-events: none;
- position: relative;
-}
-
-.loader::after {
- animation: loader 500ms infinite linear;
- border: .1rem solid #5755d9;
- border-radius: 50%;
- border-right-color: transparent;
- border-top-color: transparent;
- content: "";
- display: block;
- height: .8rem;
- left: 50%;
- margin-left: -.4rem;
- margin-top: -.4rem;
- position: absolute;
- top: 50%;
- width: .8rem;
- z-index: 1;
-}
-
-.loader.loader-lg {
- min-height: 2rem;
-}
-
-.loader.loader-lg::after {
- height: 1.6rem;
- margin-left: -.8rem;
- margin-top: -.8rem;
- width: 1.6rem;
-}
-
-@keyframes loader {
- 0% {
- transform: rotate(0deg);
- }
- 100% {
- transform: rotate(360deg);
- }
-} \ No newline at end of file
+* {} \ No newline at end of file
diff --git a/client/common/footer.component.js b/client/common/footer.component.js
deleted file mode 100644
index 7c82b44b..00000000
--- a/client/common/footer.component.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import React from 'react'
-import { Link } from 'react-router-dom'
-import { connect } from 'react-redux'
-
-export default function Footer(props) {
- return (
- <footer>
- </footer>
- );
-}
diff --git a/client/common/index.js b/client/common/index.js
index ad9fe5e1..cfb34b32 100644
--- a/client/common/index.js
+++ b/client/common/index.js
@@ -1,23 +1,15 @@
-import Header from 'vcat-header'
-
-import ActiveLink from './activeLink.component'
import Classifier from './classifier.component'
import DetectionBoxes from './detectionBoxes.component'
import DetectionList from './detectionList.component'
// import Header from './header.component'
-import Footer from './footer.component'
import Loader from './loader.component'
import Sidebar from './sidebar.component'
import Gate from './gate.component'
-import Keyframe from './keyframe.component'
-import Keyframes from './keyframes.component'
import Video from './video.component'
import { TableObject, TableArray, TableTuples, TableRow, TableCell } from './table.component'
import './common.css'
export {
- Header,
- Footer,
Sidebar,
Loader,
Gate,
@@ -26,11 +18,8 @@ export {
TableTuples,
TableRow,
TableCell,
- ActiveLink,
Classifier,
DetectionList,
DetectionBoxes,
- Keyframe,
- Keyframes,
Video,
}
diff --git a/client/common/keyframe.component.js b/client/common/keyframe.component.js
deleted file mode 100644
index c77db3ac..00000000
--- a/client/common/keyframe.component.js
+++ /dev/null
@@ -1,118 +0,0 @@
-import React from 'react'
-import { Link } from 'react-router-dom'
-import { imageUrl, timestamp, keyframeUri, widths, verify } from '../util'
-import { DetectionBoxes } from '.'
-
-import * as searchActions from '../search/search.actions'
-
-export default function Keyframe({
- verified,
- sha256,
- frame,
- score,
- isSaved,
- fps = 25,
- size = 'th',
- className,
- showHash,
- showFrame,
- showTimestamp,
- showScore,
- showSearchButton,
- showSaveButton,
- to,
- children,
- detectionList = [],
- aspectRatio = 1.777,
- onClick,
- reviewActions,
-}) {
- if (!sha256) return null
- const width = widths[size]
- const height = Math.round(width / aspectRatio)
- return (
- <div className={(className || 'keyframe') + (isSaved ? ' isSaved' : '')}>
- <div className="thumbnail">
- <PossiblyExternalLink to={to || keyframeUri(sha256, frame)} onClick={onClick}>
- <img
- alt={'Frame #' + frame}
- src={imageUrl(verified, sha256, frame, size)}
- width={width}
- height={height}
- onClick={onClick}
- />
- {detectionList.map(({ labels, detections }, i) => (
- <DetectionBoxes
- key={i}
- labels={labels}
- detections={detections}
- width={width}
- height={height}
- />
- ))}
- </PossiblyExternalLink>
- {(reviewActions && (showSearchButton || showSaveButton)) &&
- <label className='searchButtons'>
- {showSearchButton &&
- <Link
- to={searchActions.publicUrl.searchByVerifiedFrame(verified, sha256, frame)}
- className='btn'
- >
- Search
- </Link>
- }
- {showSaveButton && (isSaved
- ? <button
- onClick={() => reviewActions.unsave({ hash: sha256, frame, verified })}
- className={'btn btn-primary saved'}
- >
- {'Saved'}
- </button>
- : <button
- onClick={() => reviewActions.save({ hash: sha256, frame, verified })}
- className={'btn btn save'}
- >
- {'Save'}
- </button>
- )}
- </label>
- }
- </div>
- {(showHash || showFrame || showTimestamp || showScore) &&
- <label>
- {showHash &&
- <small>
- <Link to={searchActions.publicUrl.browse(sha256)}>
- <span
- title={sha256}
- className={'sha256 ' + verify(verified)}
- >
- {'▶ '}
- {sha256.substr(0, 6)}
- </span>
- </Link>
- </small>
- }
- {showFrame &&
- <small>
- <span>{'Frame #'}{frame}</span>
- </small>
- }
- {showTimestamp && <small>{timestamp(frame, fps)}</small>}
- {showScore && !!score && <small>{score}</small>}
- </label>
- }
- {children}
- </div>
- )
-}
-
-const PossiblyExternalLink = props => {
- if (props.onClick) {
- return props.children
- }
- if (props.to.match(/^http/)) {
- return <a href={props.to} target='_blank' rel='noopener noreferrer'>{props.children}</a>
- }
- return <Link {...props} />
-}
diff --git a/client/common/keyframes.component.js b/client/common/keyframes.component.js
deleted file mode 100644
index 62eda45e..00000000
--- a/client/common/keyframes.component.js
+++ /dev/null
@@ -1,95 +0,0 @@
-import React from 'react'
-import { Link } from 'react-router-dom'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import { Keyframe } from '.'
-import * as reviewActions from '../review/review.actions'
-import * as searchActions from '../search/search.actions'
-
-function Keyframes(props) {
- // console.log(props)
- let {
- frames,
- groupByHash,
- } = props
- let minDistance = 0
- if (frames && frames.length) {
- minDistance = frames[0].distance || 0
- }
- if (!groupByHash) {
- return (
- <KeyframeList
- minDistance={minDistance}
- {...props}
- />
- )
- }
- const frameGroups = frames.reduce((a, b) => {
- if (a[b.hash]) {
- a[b.hash].push(b)
- } else {
- a[b.hash] = [b]
- }
- return a
- }, {})
- return Object.keys(frameGroups)
- .map(hash => [frameGroups[hash].length, hash])
- .sort((a, b) => b[0] - a[0])
- .map(([count, hash]) => (
- <KeyframeList
- {...props}
- count={count}
- key={hash}
- minDistance={minDistance}
- frames={frameGroups[hash]}
- label={hash}
- />
- ))
-}
-
-function KeyframeList(props) {
- let {
- saved = {},
- frames,
- options,
- review,
- search,
- minDistance,
- label,
- count,
- ...frameProps
- } = props
- if (!frames) return null
- return (
- <div className={label ? 'keyframes keyframeGroup' : 'keyframes'}>
- {label && <h4><Link to={searchActions.publicUrl.browse(label)}>{label}</Link> ({count})</h4>}
- {frames.map(({ hash, frame, verified, distance }) => (
- <Keyframe
- key={hash + '_' + frame}
- sha256={hash}
- frame={frame}
- score={100 - Math.round(distance - minDistance) + '%'}
- verified={verified}
- isSaved={!!saved[hash] && !!saved[hash].frames && !!saved[hash].frames[parseInt(frame, 10)]}
- size={options.thumbnailSize}
- onClick={() => review.toggleSaved({ verified, hash, frame })}
- reviewActions={review}
- {...frameProps}
- />
- ))}
- </div>
- )
-}
-
-const mapStateToProps = state => ({
- saved: state.review.saved,
- options: state.search.options,
-})
-
-const mapDispatchToProps = dispatch => ({
- review: bindActionCreators({ ...reviewActions }, dispatch),
- search: bindActionCreators({ ...searchActions }, dispatch),
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(Keyframes)
diff --git a/client/common/loader.component.js b/client/common/loader.component.js
index 6795424b..5930c63e 100644
--- a/client/common/loader.component.js
+++ b/client/common/loader.component.js
@@ -1,10 +1,11 @@
-import React, { Component } from 'react'
+import React from 'react'
export default function Loader() {
return (
<div className='loaderWrapper'>
<div className='loader'>
+ <img src="/assets/img/loader.gif" />
</div>
</div>
)
-} \ No newline at end of file
+}
diff --git a/client/common/sidebar.component.js b/client/common/sidebar.component.js
index 487f3289..afbf8c8c 100644
--- a/client/common/sidebar.component.js
+++ b/client/common/sidebar.component.js
@@ -1,32 +1,13 @@
import React, { Component } from 'react'
-import { NavLink } from 'react-router-dom'
import { connect } from 'react-redux'
class Sidebar extends Component {
render() {
- const { hash } = this.props
- if (!hash) {
- return (
- <div className="sidebar">
- </div>
- )
- }
return (
<div className="sidebar">
- <h4>Media</h4>
- <NavLink to={'/metadata/' + hash + '/summary/'}>Summary</NavLink>
- <NavLink to={'/metadata/' + hash + '/mediaRecord/'}>Media Record</NavLink>
- <NavLink to={'/metadata/' + hash + '/mediaInfo/'}>Media Info</NavLink>
- <NavLink to={'/metadata/' + hash + '/sugarcube/'}>Sugarcube</NavLink>
-
- <h4>Keyframes</h4>
- <NavLink to={'/metadata/' + hash + '/keyframe/'}>Keyframe</NavLink>
-
- <h4>Detectors</h4>
- <NavLink to={'/metadata/' + hash + '/places365/'}>Places 365</NavLink>
- <NavLink to={'/metadata/' + hash + '/coco/'}>Coco</NavLink>
</div>
)
+ // <NavLink to={'/metadata/' + hash + '/summary/'}>Summary</NavLink>
}
}
diff --git a/client/faceSearch/faceSearch.query.js b/client/faceSearch/faceSearch.query.js
index 1261269d..8302e437 100644
--- a/client/faceSearch/faceSearch.query.js
+++ b/client/faceSearch/faceSearch.query.js
@@ -2,9 +2,14 @@ import React, { Component } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
+import { Loader } from '../common'
import * as actions from './faceSearch.actions'
class FaceSearchQuery extends Component {
+ state = {
+ image: null
+ }
+
upload(e) {
const { payload } = this.props
const files = e.dataTransfer ? e.dataTransfer.files : e.target.files
@@ -15,20 +20,32 @@ class FaceSearchQuery extends Component {
if (file && file.type.match('image.*')) break
}
if (!file) return
+ var fr = new FileReader();
+ fr.onload = () => {
+ fr.onload = null
+ this.setState({ image: fr.result })
+ }
+ fr.readAsDataURL(files[0]);
this.props.actions.upload(this.props.payload, file)
}
render() {
const { result } = this.props
+ const { image } = this.state
+ const style = {}
+ if (image) {
+ style.backgroundImage = 'url(' + image + ')'
+ style.backgroundSize = 'cover'
+ }
return (
<div className='query row'>
<div className='uploadContainer'>
{result.loading ?
- <div className='loading'>
- Loading...
+ <div className='loading' style={style}>
+ <Loader />
</div>
:
- <div>
+ <div style={style}>
<img src="/assets/img/icon_camera.svg" />
<input
type="file"