Skip to content
Permalink
Browse files

Views: Set up animations

I ran into so many issues... But I think I've almost got it perfect. I
may tweak it at some other point. Now to add the header.
  • Loading branch information
tvillarete committed Dec 28, 2019
1 parent 73d6699 commit ceea75021e694c09864db77bf169fbffc1ec0f83
@@ -12,6 +12,7 @@
"apollo-boost": "^0.4.7",
"apollo-client": "^2.6.4",
"apollo-utilities": "^1.3.2",
"framer-motion": "^1.7.0",
"graphql": "^14.5.8",
"react": "^16.10.2",
"react-dom": "^16.10.2",
@@ -0,0 +1,44 @@
import React from "react";
import styled from "styled-components";
import { WindowOptions } from "services/window";
import { AnimatePresence } from "framer-motion";
import Window from "App/Interface/Window";

interface ContainerProps {
isHidden: boolean;
}

const Container = styled.div<ContainerProps>`
z-index: 3;
position: absolute;
height: 100%;
width: 100%;
background: white;
transition: all 0.35s;
transform: ${props => props.isHidden && "translateX(100%)"};
`;

interface Props {
windowStack: WindowOptions[];
}

const FullScreenInterface = ({ windowStack }: Props) => {
const isHidden = windowStack.length === 0;

return (
<Container isHidden={isHidden}>
<AnimatePresence>
{windowStack.map((window, index) => (
<Window
key={`window-${window.id}`}
windowStack={windowStack}
index={index}
isHidden={index < windowStack.length - 1}
/>
))}
</AnimatePresence>
</Container>
);
};

export default FullScreenInterface;
@@ -0,0 +1,63 @@
import React from "react";
import styled from "styled-components";
import { WindowOptions } from "services/window";
import Window from "App/Interface/Window";
import { AnimatePresence } from "framer-motion";

const Container = styled.div`
z-index: 2;
position: absolute;
width: 100%;
height: 100%;
display: flex;
`;

interface PanelProps {
isHidden: boolean;
}

const LeftPanel = styled.div<PanelProps>`
z-index: 1;
position: relative;
flex: 0 0 50%;
box-shadow: 0 0 24px black;
transition: all 0.35s;
transition-delay: 0.05s;
transform: ${props => props.isHidden && "translateX(-100%)"};
overflow: hidden;
`;

const RightPanel = styled.div`
position: relative;
flex: 0 0 50%;
background: white;
`;

interface Props {
windowStack: WindowOptions[];
isHidden: boolean;
}

const SplitScreenInterface = ({ windowStack, isHidden }: Props) => {
return (
<Container>
<LeftPanel isHidden={isHidden}>
<AnimatePresence>
{windowStack.map((window, index) => (
<Window
key={`window-${window.id}`}
windowStack={windowStack}
index={index}
isHidden={index < windowStack.length - 1}
/>
))}
</AnimatePresence>
</LeftPanel>
<RightPanel>
<h3>Preview</h3>
</RightPanel>
</Container>
);
};

export default SplitScreenInterface;
@@ -0,0 +1,56 @@
import React from "react";
import styled from "styled-components";
import { WindowOptions } from "services/window";
import { slideRightAnimation, noAnimation } from "animation";
import { motion } from "framer-motion";

interface ContainerProps {
index: number;
}

/** Responsible for putting the window at the proper z-index. */
export const Container = styled(motion.div)<ContainerProps>`
z-index: ${props => props.index};
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: white;
`;

interface ContentTransitionContainerProps {
isHidden: boolean;
}

/** Slides the view to the left if it isn't at the top of the stack. */
const ContentTransitionContainer = styled.div<ContentTransitionContainerProps>`
height: 100%;
transition: transform 0.3s;
transform: ${props => props.isHidden && "translateX(-100%)"};
overflow: auto;
`;

interface Props {
windowStack: WindowOptions[];
index: number;
isHidden: boolean;
}

const Window = ({ windowStack, index, isHidden }: Props) => {
const options = windowStack[index];
const firstInStack = index === 0;

return (
<Container
index={index}
{...(firstInStack ? noAnimation : slideRightAnimation)}
>
<ContentTransitionContainer isHidden={isHidden}>
<options.component />
</ContentTransitionContainer>
</Container>
);
};

export default Window;
@@ -2,44 +2,31 @@ import React from "react";
import styled from "styled-components";
import { Unit, Screen } from "components";
import { useWindowService } from "services/window";
import SplitScreenInterface from "./SplitScreenInterface";
import FullScreenInterface from "./FullScreenInterface";
import { WINDOW_TYPE } from "App/views";

const Container = styled.div`
position: relative;
display: flex;
height: 260px;
margin: ${Unit.LG} ${Unit.LG} ${Unit.XL};
border: 4px solid black;
background: white;
border-radius: ${Unit.XS};
overflow: hidden;
background: white;
animation: fadeFromBlack 0.5s;
${Screen.SM} {
@media screen and (max-height: 750px) {
margin: ${Unit.SM} ${Unit.SM} ${Unit.XL};
}
}
@keyframes fadeFromBlack {
0% {
filter: brightness(0);
}
}
`;
interface WindowContainerProps {
index: number;
}

const WindowContainer = styled.div<WindowContainerProps>`
z-index: ${props => props.index};
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: white;
overflow: auto;
${Screen.SM} {
@media screen and (max-height: 750px) {
margin: ${Unit.SM} ${Unit.SM} ${Unit.XL};
}
}
`;

/** Prevents the user from scrolling the display with a mouse. */
@@ -54,15 +41,24 @@ const Mask = styled.div`

const Interface = () => {
const { windowStack } = useWindowService();
const splitViewWindows = windowStack.filter(
window => window.type === WINDOW_TYPE.SPLIT
);
const fullViewWindows = windowStack.filter(
window => window.type === WINDOW_TYPE.FULL
);
const inCoverFlow = !!windowStack.find(
window => window.type === WINDOW_TYPE.COVER_FLOW
);

return (
<Container>
<Mask />
{windowStack.map((window, index) => (
<WindowContainer key={`window-${index}`} index={index}>
<window.component />
</WindowContainer>
))}
<SplitScreenInterface
windowStack={splitViewWindows}
isHidden={inCoverFlow || fullViewWindows.length > 0}
/>
<FullScreenInterface windowStack={fullViewWindows} />
</Container>
);
};
@@ -1,7 +1,7 @@
import React, { useState, useEffect } from "react";
import { SelectableList, SelectableListOption } from "components";
import { useScrollHandler } from "hooks";
import ViewIds, { NowPlayingView } from "App/views";
import ViewOptions, { NowPlayingView } from "App/views";
import { gql } from "apollo-boost";
import { useQuery } from "@apollo/react-hooks";
import { Song } from "services/audio";
@@ -40,15 +40,15 @@ const AlbumView = ({ name }: Props) => {
data.album.map((song, index) => ({
label: song.name,
value: () => <NowPlayingView />,
viewId: ViewIds.nowPlaying,
viewId: ViewOptions.nowPlaying.id,
songIndex: index,
playlist: data.album
}))
);
}
}, [data, error]);

const [index] = useScrollHandler(ViewIds.album, options);
const [index] = useScrollHandler(ViewOptions.album.id, options);

return (
<SelectableList loading={loading} options={options} activeIndex={index} />
@@ -1,7 +1,7 @@
import React, { useState, useEffect } from "react";
import { SelectableList, SelectableListOption } from "components";
import { useScrollHandler } from "hooks";
import ViewIds, { AlbumView } from "App/views";
import ViewOptions, { AlbumView } from "App/views";
import { gql } from "apollo-boost";
import { useQuery } from "@apollo/react-hooks";

@@ -43,13 +43,13 @@ const ArtistView = ({ name }: Props) => {
label: result.album,
value: () => <AlbumView name={result.album} />,
image: getArtwork(result.artwork),
viewId: "Album"
viewId: ViewOptions.album.id
}))
);
}
}, [data, error]);

const [index] = useScrollHandler(ViewIds.artist, options);
const [index] = useScrollHandler(ViewOptions.artist.id, options);

return (
<SelectableList loading={loading} options={options} activeIndex={index} />
@@ -1,7 +1,7 @@
import React, { useState, useEffect } from "react";
import { SelectableList, SelectableListOption } from "components";
import { useScrollHandler } from "hooks";
import ViewIds, { ArtistView } from "..";
import ViewOptions, { ArtistView } from "..";
import { gql } from "apollo-boost";
import { useQuery } from "@apollo/react-hooks";

@@ -30,14 +30,14 @@ const ArtistsView = () => {
setOptions(
data.artists.map(result => ({
label: result.artist,
viewId: ViewIds.artist,
viewId: ViewOptions.artist.id,
value: () => <ArtistView name={result.artist} />
}))
);
}
}, [data, error]);

const [index] = useScrollHandler(ViewIds.artists, options);
const [index] = useScrollHandler(ViewOptions.artists.id, options);

return (
<SelectableList loading={loading} options={options} activeIndex={index} />
@@ -1,7 +1,7 @@
import React from "react";
import { SelectableList, SelectableListOption } from "components";
import { useScrollHandler } from "hooks";
import ViewIds, { BrickGameView } from "App/views";
import ViewOptions, { BrickGameView } from "App/views";

const options: SelectableListOption[] = [
{
@@ -11,7 +11,7 @@ const options: SelectableListOption[] = [
];

const GamesView = () => {
const [index] = useScrollHandler(ViewIds.games, options);
const [index] = useScrollHandler(ViewOptions.games.id, options);

return <SelectableList options={options} activeIndex={index} />;
};

0 comments on commit ceea750

Please sign in to comment.
You can’t perform that action at this time.