2020-06-19 06:57:57 +03:00
import * as React from "react" ;
import * as Constants from "~/common/constants" ;
2020-12-04 02:34:19 +03:00
import * as Validations from "~/common/validations" ;
import * as Window from "~/common/window" ;
import * as SVG from "~/common/svg" ;
import * as Actions from "~/common/actions" ;
import * as Events from "~/common/custom-events" ;
2020-06-19 06:57:57 +03:00
import * as System from "~/components/system" ;
2020-04-09 00:29:13 +03:00
2020-11-30 08:24:22 +03:00
import { css } from "@emotion/react" ;
2020-04-09 00:29:13 +03:00
2020-06-19 06:57:57 +03:00
import ScenePage from "~/components/core/ScenePage" ;
2020-12-04 02:34:19 +03:00
import SlateMediaObjectPreview from "~/components/core/SlateMediaObjectPreview" ;
2020-08-12 11:22:28 +03:00
import DataView from "~/components/core/DataView" ;
2020-08-22 07:25:34 +03:00
import ScenePageHeader from "~/components/core/ScenePageHeader" ;
2020-04-09 00:29:13 +03:00
2020-09-08 07:04:24 +03:00
const STYLES _VIDEO _BIG = css `
display : block ;
background - color : $ { Constants . system . moonstone } ;
padding : 0 ;
outline : 0 ;
margin : 48 px auto 88 px auto ;
border - radius : 4 px ;
width : 100 % ;
box - shadow : 0 px 10 px 50 px 20 px rgba ( 0 , 0 , 0 , 0.1 ) ;
@ media ( max - width : $ { Constants . sizes . tablet } px ) {
margin : 32 px auto 64 px auto ;
}
@ media ( max - width : $ { Constants . sizes . mobile } px ) {
margin : 24 px auto 48 px auto ;
}
` ;
2020-12-04 02:34:19 +03:00
const STYLES _IMAGE _BOX = css `
cursor : pointer ;
position : relative ;
box - shadow : $ { Constants . shadow . light } ;
margin : 10 px ;
: hover {
box - shadow : $ { Constants . shadow . medium } ;
}
` ;
const STYLES _PROFILE _IMAGE _BOX = css `
background - size : cover ;
background - position : 50 % 50 % ;
position : relative ;
border - radius : 4 px ;
position : absolute ;
top : 16 px ;
left : 16 px ;
width : 24 px ;
height : 24 px ;
` ;
2020-12-08 06:04:37 +03:00
const STYLES _TEXT _AREA = css `
2020-12-04 02:34:19 +03:00
position : absolute ;
bottom : 16 px ;
left : 16 px ;
` ;
const STYLES _TITLE = css `
overflow : hidden ;
text - overflow : ellipsis ;
white - space : nowrap ;
color : $ { Constants . system . white } ;
2020-12-08 06:04:37 +03:00
font - family : $ { Constants . font . medium } ;
margin - bottom : 4 px ;
` ;
const STYLES _SECONDARY = css `
$ { STYLES _TITLE }
font - size : $ { Constants . typescale . lvlN1 } ;
margin - bottom : 0 px ;
2020-12-04 02:34:19 +03:00
` ;
const STYLES _GRADIENT = css `
background : linear - gradient (
180 deg ,
rgba ( 0 , 0 , 0 , 0 ) 0 % ,
rgba ( 0 , 0 , 0 , 0.2 ) 26.56 % ,
rgba ( 0 , 0 , 0 , 0.3 ) 100 %
) ;
backdrop - filter : blur ( 2 px ) ;
width : 100 % ;
height : 72 px ;
position : absolute ;
bottom : 0 px ;
left : 0 px ;
` ;
2020-12-08 06:04:37 +03:00
const STYLES _ACTIVITY _GRID = css `
margin : - 10 px ;
margin - top : 0 px ;
display : flex ;
flex - direction : row ;
flex - wrap : wrap ;
` ;
2020-12-04 02:34:19 +03:00
const ActivitySquare = ( { item , size } ) => {
2020-12-08 06:04:37 +03:00
let isImage = Validations . isPreviewableImage ( item . file . type ) ;
2020-12-04 02:34:19 +03:00
return (
< div css = { STYLES _IMAGE _BOX } style = { { width : size , height : size } } >
< SlateMediaObjectPreview
centeredImage
iconOnly
blurhash = { item . file . blurhash }
url = { item . file . url }
title = { item . file . title || item . file . name }
type = { item . file . type }
style = { { border : "none" } }
imageStyle = { { border : "none" } }
/ >
2020-12-08 06:04:37 +03:00
{ isImage ? < div css = { STYLES _GRADIENT } / > : null }
< div css = { STYLES _TEXT _AREA } >
{ isImage ? null : (
< div
css = { STYLES _TITLE }
style = { {
color : Constants . system . textGray ,
width : size ,
} }
>
{ item . file . title || item . file . name }
< / d i v >
) }
2020-12-04 02:34:19 +03:00
< div
2020-12-08 06:04:37 +03:00
css = { STYLES _SECONDARY }
2020-12-04 02:34:19 +03:00
style = { {
2020-12-08 06:04:37 +03:00
width : size ,
color : isImage ? Constants . system . white : Constants . system . textGrayLight ,
2020-12-04 02:34:19 +03:00
} }
>
2020-12-06 08:13:34 +03:00
{ item . slate . data . name || item . slate . slatename }
2020-12-04 02:34:19 +03:00
< / d i v >
< / d i v >
< / d i v >
) ;
} ;
const ActivityRectangle = ( { item , size } ) => {
2020-12-06 08:13:34 +03:00
let file ;
for ( let obj of item . slate ? . data ? . objects || [ ] ) {
if ( Validations . isPreviewableImage ( obj . type ) || obj . coverImage ) {
file = obj ;
}
}
let numObjects = item . slate ? . data ? . objects ? . length || 0 ;
2020-12-04 02:34:19 +03:00
return (
2020-12-08 06:04:37 +03:00
< div css = { STYLES _IMAGE _BOX } style = { { width : size * 2 + 20 , height : size } } >
2020-12-06 08:13:34 +03:00
{ file ? (
< SlateMediaObjectPreview
centeredImage
iconOnly
blurhash = { file . blurhash }
url = { file . url }
title = { file . title || file . name }
type = { file . type }
style = { { border : "none" } }
imageStyle = { { border : "none" } }
coverImage = { file . coverImage }
/ >
) : null }
2020-12-04 02:34:19 +03:00
< div css = { STYLES _GRADIENT } / >
2020-12-08 06:04:37 +03:00
< div css = { STYLES _TEXT _AREA } >
2020-12-04 02:34:19 +03:00
< div
2020-12-08 06:04:37 +03:00
css = { STYLES _TITLE }
2020-12-04 02:34:19 +03:00
style = { {
fontFamily : Constants . font . semiBold ,
2020-12-08 06:04:37 +03:00
width : size ,
2020-12-04 02:34:19 +03:00
} }
>
2020-12-06 08:13:34 +03:00
{ item . slate . data . name || item . slate . slatename }
2020-12-04 02:34:19 +03:00
< / d i v >
< div
2020-12-08 06:04:37 +03:00
css = { STYLES _SECONDARY }
2020-12-04 02:34:19 +03:00
style = { {
color : Constants . system . textGrayLight ,
2020-12-08 06:04:37 +03:00
width : size ,
2020-12-04 02:34:19 +03:00
} }
>
{ numObjects } File { numObjects == 1 ? "" : "s" }
< / d i v >
< / d i v >
< / d i v >
) ;
} ;
2020-04-09 00:29:13 +03:00
export default class SceneHome extends React . Component {
2020-12-04 02:34:19 +03:00
state = {
imageSize : 200 ,
2020-12-06 08:13:34 +03:00
activity : [ ] ,
2020-12-04 02:34:19 +03:00
} ;
async componentDidMount ( ) {
//only fetch the last x days worth of updates maybe? or last x entries of updates?
//maybe do this when get viewer, not here. So that dont' redo every time you go back to this scene. Or maybe save it to viewer so you don't have to redo it?
2020-12-08 06:04:37 +03:00
//if add multiple to a slate, maybe only send out the event for one of them? not sure
2020-12-04 02:34:19 +03:00
this . calculateWidth ( ) ;
this . debounceInstance = Window . debounce ( this . calculateWidth , 200 ) ;
window . addEventListener ( "resize" , this . debounceInstance ) ;
let activity = this . props . viewer . activity ;
let slateIds = [ ] ;
if ( activity && activity . length ) {
activity = activity . filter ( ( item ) => {
if ( item . data . type === "OTHER_USER_CREATE_SLATE" ) {
slateIds . push ( item . data . context . slate . id ) ;
}
return (
item . data . type === "OTHER_USER_CREATE_SLATE" ||
item . data . type === "OTHER_USER_CREATE_SLATE_OBJECT"
) ;
} ) ;
}
2020-12-06 08:13:34 +03:00
let slates = [ ] ;
if ( slateIds && slateIds . length ) {
let response = await Actions . getSlatesByIds ( { id : slateIds } ) ;
if ( response && response . slate ) {
slates = response . slate ;
}
}
let slateTable = { } ;
for ( let slate of slates ) {
slateTable [ slate . id ] = slate ;
}
for ( let item of activity ) {
if ( item . data . type === "OTHER_USER_CREATE_SLATE" ) {
let slate = slateTable [ item . data . context . slate . id ] ;
2020-12-08 06:04:37 +03:00
if ( slate ? . data ? . objects ? . length ) {
2020-12-06 08:13:34 +03:00
item . data . context . slate = slate ;
}
}
}
2020-12-08 06:04:37 +03:00
//NOTE(martina): remove empty slates
activity = activity . filter ( ( item ) => {
if ( item . data . type === "OTHER_USER_CREATE_SLATE_OBJECT" ) return true ;
let slate = item . data . context . slate ;
return slate ? . data ? . objects ? . length ;
} ) ;
//NOTE(martina): rearrange order to always get an even row of 6 squares
let counter = 0 ;
for ( let i = 0 ; i < activity . length ; i ++ ) {
let item = activity [ i ] ;
if ( item . data . type === "OTHER_USER_CREATE_SLATE" ) {
counter += 2 ;
} else if ( item . data . type === "OTHER_USER_CREATE_SLATE_OBJECT" ) {
counter += 1 ;
}
if ( counter === 6 ) {
counter = 0 ;
} else if ( counter > 6 ) {
let j = i - 1 ;
while ( activity [ j ] . data . type !== "OTHER_USER_CREATE_SLATE_OBJECT" ) {
j -= 1 ;
}
let temp = activity [ j ] ;
activity [ j ] = activity [ i ] ;
activity [ i ] = temp ;
counter = 0 ;
i -= 1 ;
}
}
2020-12-06 08:13:34 +03:00
this . setState ( { activity } ) ;
2020-12-08 06:04:37 +03:00
//slates with no previewable images in them?
2020-12-06 08:13:34 +03:00
//filter to remove ones you no longer follow
2020-12-04 02:34:19 +03:00
}
componentWillUnmount ( ) {
window . removeEventListener ( "resize" , this . debounceInstance ) ;
}
2020-09-08 07:29:15 +03:00
_handleCreateSlate = ( ) => {
this . props . onAction ( {
type : "NAVIGATE" ,
value : "V1_NAVIGATION_SLATES" ,
data : null ,
} ) ;
} ;
2020-12-04 02:34:19 +03:00
calculateWidth = ( ) => {
let windowWidth = window . innerWidth ;
let imageSize ;
if ( windowWidth < Constants . sizes . mobile ) {
imageSize = ( windowWidth - 2 * 24 - 20 ) / 2 ;
} else {
2020-12-08 06:04:37 +03:00
imageSize = ( windowWidth - 2 * 56 - 5 * 20 ) / 6 ;
2020-09-08 07:29:15 +03:00
}
2020-12-04 02:34:19 +03:00
this . setState ( { imageSize } ) ;
} ;
2020-07-27 04:51:51 +03:00
2020-12-04 02:34:19 +03:00
render ( ) {
2020-04-09 00:29:13 +03:00
return (
< ScenePage >
2020-12-06 08:13:34 +03:00
{ this . state . activity . length ? (
2020-12-08 06:04:37 +03:00
< div css = { STYLES _ACTIVITY _GRID } >
2020-12-06 08:13:34 +03:00
{ this . state . activity . map ( ( item ) => {
if ( item . data . type === "OTHER_USER_CREATE_SLATE" ) {
return (
< span
2020-12-08 06:04:37 +03:00
key = { item . id }
2020-12-06 08:13:34 +03:00
onClick = { ( ) =>
this . props . onAction ( {
type : "NAVIGATE" ,
value : "V1_NAVIGATION_SLATE" ,
data : { decorator : "SLATE" , ... item . data . context . slate } ,
} )
}
>
2020-12-08 06:04:37 +03:00
< ActivityRectangle size = { this . state . imageSize } item = { item . data . context } / >
2020-12-06 08:13:34 +03:00
< / s p a n >
) ;
} else if ( item . data . type === "OTHER_USER_CREATE_SLATE_OBJECT" ) {
return (
2020-12-08 06:04:37 +03:00
< span
2020-12-06 08:13:34 +03:00
key = { item . id }
2020-12-08 06:04:37 +03:00
onClick = { ( ) => {
this . props . onAction ( {
type : "NAVIGATE" ,
value : "V1_NAVIGATION_SLATE" ,
data : {
decorator : "SLATE" ,
... item . data . context . slate ,
pageState : {
cid : item . data . context . file . cid ,
} ,
} ,
} ) ;
} }
>
< ActivitySquare size = { this . state . imageSize } item = { item . data . context } / >
< / s p a n >
2020-12-06 08:13:34 +03:00
) ;
} else {
return < div > hello < / d i v > ;
}
} ) }
2020-09-08 01:16:02 +03:00
< / d i v >
2020-09-08 07:04:24 +03:00
) : (
2020-09-08 07:29:15 +03:00
< React . Fragment >
2020-12-06 08:13:34 +03:00
< System . P > When you ' re ready , create a slate ! < / S y s t e m . P >
< br / >
< System . ButtonPrimary onClick = { this . _handleCreateSlate } >
Create a slate
< / S y s t e m . B u t t o n P r i m a r y >
2020-09-08 07:29:15 +03:00
< video
css = { STYLES _VIDEO _BIG }
autoPlay
loop
muted
2020-09-12 06:43:28 +03:00
src = "https://slate.textile.io/ipfs/bafybeienjmql6lbtsaz3ycon3ttliohcl7qbquwvny43lhcodky54z65cy"
2020-09-08 07:29:15 +03:00
type = "video/m4v"
playsInline
style = { {
2020-09-12 06:43:28 +03:00
backgroundImage : ` url('https://slate.textile.io/ipfs/bafybeienjmql6lbtsaz3ycon3ttliohcl7qbquwvny43lhcodky54z65cy') ` ,
2020-09-08 07:29:15 +03:00
borderRadius : ` 4px ` ,
width : ` 100% ` ,
boxShadow : ` 0px 10px 50px 20px rgba(0, 0, 0, 0.1) ` ,
backgroundSize : ` cover ` ,
} }
/ >
< / R e a c t . F r a g m e n t >
2020-09-08 07:04:24 +03:00
) }
2020-04-09 00:29:13 +03:00
< / S c e n e P a g e >
) ;
}
}