diff --git a/js/components/MediaLibraryWindow/LibraryLayout.tsx b/js/components/MediaLibraryWindow/LibraryLayout.tsx new file mode 100644 index 00000000..3d1b12ad --- /dev/null +++ b/js/components/MediaLibraryWindow/LibraryLayout.tsx @@ -0,0 +1,178 @@ +import React, { ReactNode } from "react"; +import { connect } from "react-redux"; +import GenWindow from "../GenWindow"; +import { WINDOWS } from "../../constants"; +import { AppState, SkinGenExColors } from "../../types"; +import * as Selectors from "../../selectors"; + +interface StateProps { + skinGenExColors: SkinGenExColors; +} + +interface OwnProps { + sidebar: ReactNode; + artists: ReactNode; + albums: ReactNode; + tracks: ReactNode; +} + +type Props = StateProps & OwnProps; + +interface State { + sidebarWidth: number; + topPlaylistSectionHeight: number; + artistsPanelWidth: number; +} + +const DIVIDER_WIDTH = 9; +// TODO: Tune these +const SIDEBAR_MIN = 25; +const SIDEBAR_MAX = 200; + +class LibraryLayout extends React.Component { + constructor(props: Props) { + super(props); + this.state = { + sidebarWidth: 100, // Pixels + topPlaylistSectionHeight: 0.25, // Percent + artistsPanelWidth: 0.5, // Percent + }; + } + + _onMouseMove(cb: (e: MouseEvent) => void) { + const handleMouseUp = () => { + document.removeEventListener("mousemove", cb); + document.removeEventListener("mouseup", handleMouseUp); + }; + // TODO: Technically there's a leak here since the component could unmount while we are moving + document.addEventListener("mousemove", cb); + document.addEventListener("mouseup", handleMouseUp); + } + + _handleSidebarMouseDown = (e: React.MouseEvent) => { + const { pageX: startX } = e; + const initialWidth = this.state.sidebarWidth; + this._onMouseMove((moveEvent: MouseEvent) => { + let sidebarWidth = initialWidth + moveEvent.pageX - startX; + if (sidebarWidth < SIDEBAR_MIN) { + sidebarWidth = 0; + } + sidebarWidth = Math.min(sidebarWidth, SIDEBAR_MAX); + + this.setState({ sidebarWidth }); + }); + }; + + _handlePlaylistResizeMouseDown = ( + e: React.MouseEvent, + windowHeight: number + ) => { + const { pageY: startY } = e; + const avaliableHeight = windowHeight - DIVIDER_WIDTH; + const initialHeight = avaliableHeight * this.state.topPlaylistSectionHeight; + + this._onMouseMove((moveEvent: MouseEvent) => { + const deltaY = moveEvent.pageY - startY; + const topPlaylistSectionPixelHeight = initialHeight + deltaY; + this.setState({ + topPlaylistSectionHeight: + topPlaylistSectionPixelHeight / avaliableHeight, + }); + }); + }; + + _handleArtistsResizeMouseDown = ( + e: React.MouseEvent, + windowWidth: number + ) => { + const { pageX: startX } = e; + const avaliableWidth = + windowWidth - DIVIDER_WIDTH - this.state.sidebarWidth; + const initialWidth = avaliableWidth * this.state.artistsPanelWidth; + + this._onMouseMove((moveEvent: MouseEvent) => { + const deltaX = moveEvent.pageX - startX; + const artistsPanelPixelWidth = initialWidth + deltaX; + this.setState({ + artistsPanelWidth: artistsPanelPixelWidth / avaliableWidth, + }); + }); + }; + + render() { + return ( + + {({ width, height }) => ( +
+ {this.state.sidebarWidth === 0 ?
: this.props.sidebar} +
+
+
+
+
+ {this.props.artists} +
) => + this._handleArtistsResizeMouseDown(e, width) + } + > +
+
+ {this.props.albums} +
+
) => + this._handlePlaylistResizeMouseDown(e, height) + } + > +
+
+
{this.props.tracks}
+
+
+ )} + + ); + } +} + +const mapStateToProps = (state: AppState): StateProps => { + return { + skinGenExColors: Selectors.getSkinGenExColors(state), + }; +}; +export default connect(mapStateToProps)(LibraryLayout); diff --git a/js/components/MediaLibraryWindow/TracksTable.tsx b/js/components/MediaLibraryWindow/TracksTable.tsx index c86ed6ca..3302b83a 100644 --- a/js/components/MediaLibraryWindow/TracksTable.tsx +++ b/js/components/MediaLibraryWindow/TracksTable.tsx @@ -30,6 +30,7 @@ class TracksTable extends React.Component { display: "flex", flexDirection: "column", flexGrow: 2, + height: "100%", }} >
{ - constructor(props: Props) { - super(props); - this.state = { - sidebarWidth: 100, - topPlaylistSectionHeight: 200, - artistsPanelWidth: 150, - }; - } - - _onMouseMove(cb: (e: MouseEvent) => void) { - const handleMouseUp = () => { - document.removeEventListener("mousemove", cb); - document.removeEventListener("mouseup", handleMouseUp); - }; - document.addEventListener("mousemove", cb); - document.addEventListener("mouseup", handleMouseUp); - } - - _handleSidebarMouseDown = (e: React.MouseEvent) => { - const { pageX: startX } = e; - const initialWidth = this.state.sidebarWidth; - this._onMouseMove((moveEvent: MouseEvent) => { - this.setState({ - sidebarWidth: initialWidth + moveEvent.pageX - startX, - }); - }); - }; - - _handlePlaylistResizeMouseDown = (e: React.MouseEvent) => { - const { pageY: startY } = e; - const initialHeight = this.state.topPlaylistSectionHeight; - this._onMouseMove((moveEvent: MouseEvent) => { - this.setState({ - topPlaylistSectionHeight: initialHeight + moveEvent.pageY - startY, - }); - }); - }; - - _handleArtistsResizeMouseDown = (e: React.MouseEvent) => { - const { pageX: startX } = e; - const initialWidth = this.state.artistsPanelWidth; - this._onMouseMove((moveEvent: MouseEvent) => { - this.setState({ - artistsPanelWidth: initialWidth + moveEvent.pageX - startX, - }); - }); - }; - +export default class MediaLibraryWindow extends React.Component<{}> { render() { return ( - - {() => ( -
-
- -
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
- )} - + } + artists={} + albums={} + tracks={} + /> ); } } - -const mapStateToProps = (state: AppState) => { - return { - skinGenExColors: Selectors.getSkinGenExColors(state), - }; -}; -export default connect(mapStateToProps)(MediaLibraryWindow);