grid mostly there

This commit is contained in:
2018-12-27 15:17:23 -08:00
parent 907d15d481
commit 9c052aebd2
14 changed files with 1418 additions and 24 deletions

69
src/components/grid.tsx Normal file
View File

@@ -0,0 +1,69 @@
import { Picture } from "./picture";
import * as Model from "../model";
import * as React from "react";
export interface Props {
images: Model.Images;
onImageSelected: (key: string) => void;
selectedImage: string | null;
width: number;
}
export const ROW_HEIGHT = 200;
export const MOBILE_ROW_HEIGHT = 100;
export class Grid extends React.PureComponent<Props, {}> {
static displayName = "Grid";
render() {
const keys = Object.keys(this.props.images);
let row: string[] = [];
const rows: string[][] = [];
const rowWidths: number[] = [];
let rowWidth = 0;
keys.forEach(key => {
const image = this.props.images[key];
const newWidth = rowWidth + (image.width/image.height);
const height = this.props.width / newWidth;
if (height < this._rowHeight()) {
rows.push(row);
rowWidths.push(rowWidth);
row = [];
rowWidth = (image.width/image.height);
} else {
rowWidth = newWidth;
}
row.push(key);
});
rows.push(row);
rowWidths.push(rowWidth);
const images = rows.map((row, idx) => {
const scale = this.props.width / rowWidths[idx];
const pics = row.map(key => {
const image = this.props.images[key];
return <Picture
image={image}
onClick={() => this.props.onImageSelected(key)}
selected={this.props.selectedImage === key}
src={key}
key={key}
width={image.width/image.height * scale}
/>
});
return <div className="Grid-row" style={{height: scale + "px"}} key={row.join(",")}>{pics}</div>;
});
return <div className="Grid">{images}</div>;
}
private _rowHeight = (): number =>
this.props.width > 500 ? ROW_HEIGHT : MOBILE_ROW_HEIGHT;
}

View File

@@ -0,0 +1,44 @@
import * as Model from "../model";
import * as React from "react";
export interface Props {
src: string;
image: Model.Image;
onClick: () => void;
selected?: boolean;
width: number;
}
export class Picture extends React.PureComponent<Props, {}> {
static displayName = "Picture";
render() {
const src = `img/600/${this.props.src}`;
return <img
className={ this.props.selected ? "Picture-selected" : ""}
onClick={this.props.onClick}
srcSet={this._srcset()}
src={src}
width={ this.props.selected ? "100%" : this.props.width + "px" }
/>;
}
private _srcset = (): string => {
const srcs: string[] = [];
Model.SIZES.forEach(size => {
const width = this.props.image.width > this.props.image.height
? size
: this.props.image.width / this.props.image.height * size;
const scale = width / this.props.width;
if (scale >= 1) {
srcs.push(`img/${size}/${this.props.src} ${scale}x`);
}
});
return srcs.join(",");
}
}

52
src/components/root.tsx Normal file
View File

@@ -0,0 +1,52 @@
import { Grid } from "./grid";
import * as Model from "../model";
import * as React from "react";
export interface Props {}
export interface State {
images: Model.Images;
selectedIamge?: string | null;
width: number;
}
export class Root extends React.PureComponent<Props, State> {
static displayName = "Root";
state = {
images: {},
selectedImage: null,
width: window.innerWidth
}
componentDidMount() {
window.fetch(Model.URL)
.then(data => data.json())
.then(json => this.setState({ images: json }))
.catch(e => console.error("Error fetching data", e));
window.onresize = () => {
this.setState({ width: window.innerWidth });
}
}
render() {
return <div className="Root">
<h1>Ski</h1>
<hr />
<Grid
images={ this.state.images }
onImageSelected={ this._onImageSelected }
selectedImage={ this.state.selectedImage }
width={ this.state.width } />
</div>;
}
private _onImageSelected = (key: string) => {
this.setState(state => ({
...state,
selectedImage: key
}));
}
}