diff --git a/src/components/App.jsx b/src/components/App.jsx
index ac12e14..f876253 100644
--- a/src/components/App.jsx
+++ b/src/components/App.jsx
@@ -1,13 +1,11 @@
import '../scss/main.scss'
import React from 'react'
-import Dashboard from './Dashboard.jsx'
+import Layout from './Layout'
class App extends React.Component {
render () {
return (
-
{
actions.updateSource(null)
diff --git a/src/components/Overlay/Content.js b/src/components/Overlay/Content.js
new file mode 100644
index 0000000..9c1db50
--- /dev/null
+++ b/src/components/Overlay/Content.js
@@ -0,0 +1,61 @@
+import React from 'react'
+import { Player } from 'video-react'
+import Img from 'react-image'
+import Md from './Md'
+import Spinner from '../presentational/Spinner'
+import NoSource from '../presentational/NoSource'
+
+export default ({ media, viewIdx }) => {
+ const el = document.querySelector(`.source-media-gallery`)
+ const shiftW = el ? el.getBoundingClientRect().width : 0
+
+ function renderMedia (media) {
+ const { path, type } = media
+ switch (type) {
+ case 'Image':
+ return (
+
+

}
+ unloader={}
+ />
+
+ )
+ case 'Video':
+ return (
+
+ )
+ case 'Text':
+ return (
+
+ }
+ unloader={() => this.renderError()}
+ />
+
+ )
+ default:
+ return (
+
+ )
+ }
+ }
+
+ return (
+
+ {media.map((m) => renderMedia(m))}
+
+ )
+}
diff --git a/src/components/Overlay/Controls.js b/src/components/Overlay/Controls.js
new file mode 100644
index 0000000..5351ece
--- /dev/null
+++ b/src/components/Overlay/Controls.js
@@ -0,0 +1,36 @@
+import React from 'react'
+
+export default ({ viewIdx, paths, onShiftHandler }) => {
+ const backArrow = viewIdx !== 0 ? (
+ onShiftHandler(-1)}
+ >
+
+ arrow_left
+
+
+ ) : null
+ const forwardArrow = viewIdx < paths.length - 1 ? (
+ onShiftHandler(1)}
+ >
+
+ arrow_right
+
+
+ ) : null
+
+ if (paths.length > 1) {
+ return (
+
+ {backArrow}
+ {forwardArrow}
+
+ )
+ }
+ return (
+
+ )
+}
diff --git a/src/components/presentational/LoadingOverlay.js b/src/components/Overlay/Loading.js
similarity index 100%
rename from src/components/presentational/LoadingOverlay.js
rename to src/components/Overlay/Loading.js
diff --git a/src/components/Md.jsx b/src/components/Overlay/Md.js
similarity index 100%
rename from src/components/Md.jsx
rename to src/components/Overlay/Md.js
diff --git a/src/components/Overlay/Media.js b/src/components/Overlay/Media.js
new file mode 100644
index 0000000..f7df127
--- /dev/null
+++ b/src/components/Overlay/Media.js
@@ -0,0 +1,88 @@
+import React from 'react'
+import Content from './Content'
+import Controls from './Controls'
+import { selectTypeFromPath } from '../../js/utilities'
+
+class SourceOverlay extends React.Component {
+ constructor () {
+ super()
+ this.state = { idx: 0 }
+ this.onShiftGallery = this.onShiftGallery.bind(this)
+ }
+
+ getTypeCounts (media) {
+ return media.reduce(
+ (acc, vl) => {
+ acc[vl.type] += 1
+ return acc
+ },
+ { Image: 0, Video: 0, Text: 0 }
+ )
+ }
+
+ onShiftGallery (shift) {
+ // no more left
+ if (this.state.idx === 0 && shift === -1) return
+ // no more right
+ if (this.state.idx === this.props.source.paths.length - 1 && shift === 1) return
+ this.setState({ idx: this.state.idx + shift })
+ }
+
+ render () {
+ if (typeof (this.props.source) !== 'object') {
+ return this.renderError()
+ }
+ const { url, title, paths, date, type } = this.props.source
+ const shortenedTitle = title.substring(0, 100)
+
+ return (
+
+
+
+ close
+
+
+
+
{shortenedTitle}
+
+
+
+
e.stopPropagation()}>
+
+
+
+
+
+
+
+
+
+
+ {/*
*/}
+ {/* {title ?
{title}
: null} */}
+ {/*
{desc}
*/}
+ {/*
*/}
+
+
+
+ {type ?
Media type
: null}
+ {type ?
perm_media{type}
: null}
+
+
+ {date ?
Date
: null}
+ {date ?
today{date}
: null}
+
+
+
+
+
+
+
+ )
+ }
+}
+
+export default SourceOverlay
diff --git a/src/components/SourceOverlay.jsx b/src/components/SourceOverlay.jsx
deleted file mode 100644
index 5b3a254..0000000
--- a/src/components/SourceOverlay.jsx
+++ /dev/null
@@ -1,216 +0,0 @@
-import React from 'react'
-import Img from 'react-image'
-import { Player } from 'video-react'
-import Md from './Md.jsx'
-import Spinner from './presentational/Spinner'
-import NoSource from './presentational/NoSource'
-// TODO: move render functions into presentational components
-
-class SourceOverlay extends React.Component {
- constructor () {
- super()
- this.state = { idx: 0 }
- }
-
- renderImage (path) {
- return (
-
-

}
- unloader={}
- />
-
- )
- }
-
- renderVideo (path) {
- return (
-
- )
- }
-
- renderText (path) {
- return (
-
- }
- unloader={() => this.renderError()}
- />
-
- )
- }
-
- renderNoSupport (ext) {
- return (
-
- )
- }
-
- toMedia (path) {
- let type
- switch (true) {
- case /\.(png|jpg)$/.test(path):
- type = 'Image'; break
- case /\.(mp4)$/.test(path):
- type = 'Video'; break
- case /\.(md)$/.test(path):
- type = 'Text'; break
- default:
- type = 'Unknown'; break
- }
- return { type, path }
- }
-
- getTypeCounts (media) {
- return media.reduce(
- (acc, vl) => {
- acc[vl.type] += 1
- return acc
- },
- { Image: 0, Video: 0, Text: 0 }
- )
- }
-
- _renderPath (media) {
- const { path, type } = media
- switch (type) {
- case 'Image':
- return this.renderImage(path)
- case 'Video':
- return this.renderVideo(path)
- case 'Text':
- return this.renderText(path)
- default:
- return this.renderNoSupport(path.split('.')[1])
- }
- }
-
- _renderCounts (counts) {
- const strFor = type =>
- counts[type] > 0
- ? `${counts[type]} ${type.toLowerCase()}${counts[type] > 1 ? 's' : ''}`
- : ''
- const img = strFor('Image')
- const vid = strFor('Video')
- const txt = strFor('Text')
-
- return (
-
- {img || ''}
- {(img && vid) ? `, ${vid}` : (vid || '')}
- {((img || vid) && txt) ? `, ${txt}` : (txt || '')}
-
- )
- }
-
- _renderContent (media) {
- const el = document.querySelector(`.source-media-gallery`)
- const shiftW = el ? el.getBoundingClientRect().width : 0
- return (
-
- {media.map((m) => this._renderPath(m))}
-
- )
- }
-
- onShiftGallery (shift) {
- // no more left
- if (this.state.idx === 0 && shift === -1) return
- // no more right
- if (this.state.idx === this.props.source.paths.length - 1 && shift === 1) return
- this.setState({ idx: this.state.idx + shift })
- }
-
- _renderControls () {
- const backArrow = this.state.idx !== 0 ? (
- this.onShiftGallery(-1)}
- >
-
-
- ) : null
- const forwardArrow = this.state.idx < this.props.source.paths.length - 1 ? (
- this.onShiftGallery(1)}
- >
-
-
- ) : null
-
- if (this.props.source.paths.length > 1) {
- return (
-
- {backArrow}
- {forwardArrow}
-
- )
- }
- return (
-
- )
- }
-
- render () {
- if (typeof (this.props.source) !== 'object') {
- return this.renderError()
- }
- const { url, title, paths, date, type, desc } = this.props.source
- const media = paths.map(this.toMedia)
-
- return (
-
-
e.stopPropagation()}>
-
-
-
-
-
{this.props.source.title.substring(0, 200)}
-
-
- {this._renderContent(media)}
- {this._renderControls()}
-
-
-
- {/*
{`${this.state.idx+1} / ${paths.length}`}
*/}
- {title ?
{title}
: null}
-
{desc}
-
-
-
-
- {type ?
Media type
: null}
- {type ?
perm_media{type}
: null}
-
-
- {date ?
Date
: null}
- {date ?
today{date}
: null}
-
-
-
-
-
-
- )
- }
-}
-
-export default SourceOverlay
diff --git a/src/js/utilities.js b/src/js/utilities.js
index 8d04788..00d9987 100644
--- a/src/js/utilities.js
+++ b/src/js/utilities.js
@@ -136,3 +136,18 @@ export function toggleFlagAC (flag) {
}
})
}
+
+export function selectTypeFromPath (path) {
+ let type
+ switch (true) {
+ case /\.(png|jpg)$/.test(path):
+ type = 'Image'; break
+ case /\.(mp4)$/.test(path):
+ type = 'Video'; break
+ case /\.(md)$/.test(path):
+ type = 'Text'; break
+ default:
+ type = 'Unknown'; break
+ }
+ return { type, path }
+}
diff --git a/src/scss/main.scss b/src/scss/main.scss
index 21656c9..1c10ad5 100644
--- a/src/scss/main.scss
+++ b/src/scss/main.scss
@@ -7,7 +7,7 @@
@import 'header';
@import 'cardstack';
@import 'narrativecard';
-@import 'sourceoverlay';
+@import 'overlay';
@import 'map';
@import 'timeline';
@import 'tag-filters';
diff --git a/src/scss/sourceoverlay.scss b/src/scss/overlay.scss
similarity index 70%
rename from src/scss/sourceoverlay.scss
rename to src/scss/overlay.scss
index 6909eac..ae5367e 100644
--- a/src/scss/sourceoverlay.scss
+++ b/src/scss/overlay.scss
@@ -6,37 +6,100 @@ $vimeo-height: $panel-height / 2;
$padding: 20px;
$header-inset: 10px;
+$banner-height: 100px;
+
.mo-overlay {
display: flex;
flex-direction: column;
- justify-content: center;
+ // justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
- background-color: rgba(239, 239, 239, 0.5);
+ background-color: rgba(0,0,0, 0.85);
z-index: 20;
}
.mo-container {
- background-color: rgba(239, 239, 239, 0.9);
+ margin-top: $banner-height;
+ background-color: transparent;
display: flex;
flex-direction: column;
align-items: center;
- height: $panel-height;
- max-height: calc(100% - 40px);
+ height: calc(100vh - 350px);
+ max-height: calc(100vh - 350px);
width: $panel-width;
max-width: 90vw;
box-shadow: 0 19px 19px rgba(0, 0, 0, 0.3), 0 15px 12px rgba(0, 0, 0, 0.22);
+
+}
+
+$overlay-bg: rgba(239,239,239,0.9);
+
+.mo-banner {
+ position: fixed;
+ min-height: 100px;
+ background-color: transparent;
+ top: 0;
+ width: 100%;
+ display: flex;
+ justify-content: flex-start;
+ align-items: stretch;
+ flex-direction: row;
+
+ .mo-banner-close {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-width: $banner-height;
+ .material-icons {
+ font-size: 40pt;
+ background-color: transparent;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ transition: 0.3s all ease;
+ color: $overlay-bg;
+
+ &:hover {
+ text-decoration: none;
+ cursor: pointer;
+ color: white;
+ }
+ }
+ }
+
+ .mo-banner-content {
+ flex: 11;
+ text-align: center;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ h3 {
+ border-radius: 2px;
+ padding: 10px 15px;
+ background-color: transparent;
+ color: $overlay-bg;
+ margin-left: -$banner-height;
+ }
+ }
+}
+
+.media-gallery-controls {
+ height: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: -50%;
+
.back, .next {
- width: 30px;
- max-width: 30px;
- max-height: 30px;
- height: 30px;
- background: $darkgrey;
+ position: fixed;
+ bottom: 0;
+ height: 170px;
+ background: transparent;
color: $offwhite;
cursor: pointer;
box-shadow: 0 19px 19px rgba(0, 0, 0, 0.3), 0 15px 12px rgba(0, 0, 0, 0.22);
@@ -44,6 +107,18 @@ $header-inset: 10px;
z-index: 1;
}
+ .centerer {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .material-icons {
+ font-size: 40pt;
+ }
+
.back {
left: 10px;
svg path { transform: translate(17px,15px)rotate(-90deg)}
@@ -55,32 +130,6 @@ $header-inset: 10px;
}
}
-.mo-header {
- min-height: 42px;
- max-height: 42px;
- width: 100%;
- display: flex;
- flex-direction: row;
- background-color: black;
- color: white;
-
- .mo-header-close {
- display: flex;
- justify-content: center;
- align-items: center;
- margin-left: $header-inset + 8px;
- }
-
- .mo-header-text {
- flex: 1;
- display: flex;
- align-items: center;
- justify-content: flex-end;
- padding-right: $padding;
- font-family: "Lato", Helvetica, sans-serif;
- }
-}
-
.mo-media-container {
flex: 1;
flex-direction: row;
@@ -90,41 +139,38 @@ $header-inset: 10px;
box-sizing: border-box;
width: 100%;
max-height: calc(#{$panel-height} - 100px);
- padding: 20px;
font-family: "Lato", Helvetica, sans-serif;
- .media-player {
- width: 100%;
- max-width: $vimeo-width;
- }
-
.media-content {
display: flex;
flex-direction: column;
}
- .media-gallery-controls {
- height: 100%;
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-top: -50%;
- }
-
// NB: topcushion seems to be necessary with certain overflows..
&.topcushion {
padding-top: 150px;
}
}
+
+.mo-footer {
+ position: fixed;
+ height: 250px;
+ background-color: transparent;
+ width: 100%;
+ opacity: 0.9;
+ bottom: 0;
+ display: flex;
+ justify-content: center;
+}
+
.mo-meta-container {
+ color: $overlay-bg;
display: flex;
flex-direction: column;
justify-content: center;
box-sizing: border-box;
min-height: 100px;
- width: 100%;
- // padding: $padding;
.mo-box-title {
display: flex;
@@ -137,8 +183,7 @@ $header-inset: 10px;
display: flex;
flex-direction: row;
justify-content: space-around;
- max-width: $panel-width;
- width: 100%;
+ width: $panel-width;
padding: $padding 0;
border-top: 1px solid rgb(189,189,189);
font-family: "Lato", Helvetica, sans-serif;
@@ -165,9 +210,8 @@ $header-inset: 10px;
a {
font-size: $large;
- color: $darkgrey;
- border-bottom: 1px solid $red;
- &:hover { border-bottom: 1px solid $darkgrey; }
+ color: $yellow;
+ border-bottom: 1px solid $yellow;
}
}
@@ -176,17 +220,6 @@ $header-inset: 10px;
}
}
-.mo-controls {
- color: white;
- width: $vimeo-width;
- background-color: black;
-}
-
-.media-controls {
- padding: 0 50px;
-}
-
-
/* source overlay specific styles */
.no-source-container {
display: flex;
@@ -220,7 +253,6 @@ $header-inset: 10px;
}
.source-text-container {
- padding: 20px;
display: flex;
justify-content: center;
box-sizing: border-box;
@@ -230,10 +262,11 @@ $header-inset: 10px;
line-height: 1.5em;
min-width: 100%;
+ color: $overlay-bg;
+
a {
- color: $darkgrey;
- border-bottom: 1px solid $red;
- &:hover { border-bottom: 1px solid $darkgrey; color: $darkgrey; }
+ color: $yellow;
+ border-bottom: 1px solid $yellow;
}
.md-container {
@@ -261,7 +294,7 @@ $header-inset: 10px;
.source-image, .source-video {
padding: 0px;
font-family: 'Lato', Helvetica, sans-serif;
- max-width: calc(#{$panel-width} - 100px);
+ // max-width: calc(#{$panel-width} - 100px);
max-height: $panel-height;
margin: auto;
width: auto;