prettier
This commit is contained in:
@@ -3,42 +3,48 @@ import * as Model from "../model";
|
||||
import * as React from "react";
|
||||
|
||||
export interface Props {
|
||||
image: Model.Image;
|
||||
onClose: () => void;
|
||||
width: number;
|
||||
image: Model.Image;
|
||||
onClose: () => void;
|
||||
width: number;
|
||||
}
|
||||
|
||||
export class BigPicture extends React.PureComponent<Props, {}> {
|
||||
static displayName = "BigPicture";
|
||||
static displayName = "BigPicture";
|
||||
|
||||
render() {
|
||||
const src = `img/1600/${this.props.image.src}`;
|
||||
return <div className="BigPicture">
|
||||
<div
|
||||
className="BigPicture-image"
|
||||
style={{
|
||||
backgroundImage: `url(${src})`
|
||||
}}>
|
||||
</div>
|
||||
<div className="BigPicture-footer">
|
||||
<a className="BigPicture-footerLink"
|
||||
href={`img/${this.props.image.src}`}
|
||||
target="_blank">
|
||||
Download
|
||||
</a>
|
||||
<span className="BigPicture-footerLink"
|
||||
onClick={this.props.onClose}
|
||||
onKeyPress={this._keyPress}
|
||||
tabIndex={0} >
|
||||
Close
|
||||
</span>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
render() {
|
||||
const src = `img/1600/${this.props.image.src}`;
|
||||
return (
|
||||
<div className="BigPicture">
|
||||
<div
|
||||
className="BigPicture-image"
|
||||
style={{
|
||||
backgroundImage: `url(${src})`
|
||||
}}
|
||||
/>
|
||||
<div className="BigPicture-footer">
|
||||
<a
|
||||
className="BigPicture-footerLink"
|
||||
href={`img/${this.props.image.src}`}
|
||||
target="_blank"
|
||||
>
|
||||
Download
|
||||
</a>
|
||||
<span
|
||||
className="BigPicture-footerLink"
|
||||
onClick={this.props.onClose}
|
||||
onKeyPress={this._keyPress}
|
||||
tabIndex={0}
|
||||
>
|
||||
Close
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private _keyPress = (e: React.KeyboardEvent) => {
|
||||
if (e.key === "Enter") {
|
||||
this.props.onClose();
|
||||
}
|
||||
private _keyPress = (e: React.KeyboardEvent) => {
|
||||
if (e.key === "Enter") {
|
||||
this.props.onClose();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,71 +4,76 @@ import * as Model from "../model";
|
||||
import * as React from "react";
|
||||
|
||||
export interface Props {
|
||||
images: Model.Image[];
|
||||
onImageSelected: (image: Model.Image) => void;
|
||||
width: number;
|
||||
images: Model.Image[];
|
||||
onImageSelected: (image: Model.Image) => void;
|
||||
width: number;
|
||||
}
|
||||
|
||||
export const ROW_HEIGHT = 200;
|
||||
export const MOBILE_ROW_HEIGHT = 100;
|
||||
|
||||
interface Row {
|
||||
images: Model.Image[];
|
||||
width: number;
|
||||
images: Model.Image[];
|
||||
width: number;
|
||||
}
|
||||
|
||||
export class Grid extends React.PureComponent<Props, {}> {
|
||||
static displayName = "Grid";
|
||||
static displayName = "Grid";
|
||||
|
||||
render() {
|
||||
let row: Model.Image[] = [];
|
||||
const rows: Row[] = [];
|
||||
let rowWidth = 0;
|
||||
render() {
|
||||
let row: Model.Image[] = [];
|
||||
const rows: Row[] = [];
|
||||
let rowWidth = 0;
|
||||
|
||||
this.props.images.forEach(image => {
|
||||
const newWidth = rowWidth + (image.width/image.height);
|
||||
const height = this.props.width / newWidth;
|
||||
this.props.images.forEach(image => {
|
||||
const newWidth = rowWidth + image.width / image.height;
|
||||
const height = this.props.width / newWidth;
|
||||
|
||||
if (height < this._rowHeight()) {
|
||||
rows.push({
|
||||
images: row,
|
||||
width: rowWidth
|
||||
});
|
||||
|
||||
row = [];
|
||||
rowWidth = (image.width/image.height);
|
||||
} else {
|
||||
rowWidth = newWidth;
|
||||
}
|
||||
row.push(image);
|
||||
});
|
||||
if (height < this._rowHeight()) {
|
||||
rows.push({
|
||||
images: row,
|
||||
width: rowWidth
|
||||
images: row,
|
||||
width: rowWidth
|
||||
});
|
||||
|
||||
const images = rows.map(row => {
|
||||
const height = this.props.width / row.width;
|
||||
row = [];
|
||||
rowWidth = image.width / image.height;
|
||||
} else {
|
||||
rowWidth = newWidth;
|
||||
}
|
||||
row.push(image);
|
||||
});
|
||||
rows.push({
|
||||
images: row,
|
||||
width: rowWidth
|
||||
});
|
||||
|
||||
const pics = row.images.map(image => {
|
||||
return <Picture
|
||||
image={image}
|
||||
onClick={() => this.props.onImageSelected(image)}
|
||||
key={image.src}
|
||||
width={image.width/image.height * height}
|
||||
/>
|
||||
});
|
||||
return <div
|
||||
className="Grid-row"
|
||||
style={{height: height + "px"}}
|
||||
key={row.images.map(image => image.src).join(",")}>
|
||||
{pics}
|
||||
</div>;
|
||||
});
|
||||
const images = rows.map(row => {
|
||||
const height = this.props.width / row.width;
|
||||
|
||||
return <div className="Grid">{images}</div>;
|
||||
}
|
||||
const pics = row.images.map(image => {
|
||||
return (
|
||||
<Picture
|
||||
image={image}
|
||||
onClick={() => this.props.onImageSelected(image)}
|
||||
key={image.src}
|
||||
width={(image.width / image.height) * height}
|
||||
/>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<div
|
||||
className="Grid-row"
|
||||
style={{ height: height + "px" }}
|
||||
key={row.images.map(image => image.src).join(",")}
|
||||
>
|
||||
{pics}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
private _rowHeight = (): number =>
|
||||
this.props.width > 500 ? ROW_HEIGHT : MOBILE_ROW_HEIGHT;
|
||||
return <div className="Grid">{images}</div>;
|
||||
}
|
||||
|
||||
private _rowHeight = (): number =>
|
||||
this.props.width > 500 ? ROW_HEIGHT : MOBILE_ROW_HEIGHT;
|
||||
}
|
||||
|
||||
@@ -4,21 +4,26 @@ import * as Model from "../model";
|
||||
import * as React from "react";
|
||||
|
||||
export interface Props {
|
||||
imageSet: Model.ImageSet;
|
||||
onImageSelected: (img: Model.Image) => void;
|
||||
width: number;
|
||||
imageSet: Model.ImageSet;
|
||||
onImageSelected: (img: Model.Image) => void;
|
||||
width: number;
|
||||
}
|
||||
|
||||
export class ImageSet extends React.PureComponent<Props, {}> {
|
||||
static displayName = "ImageSet";
|
||||
static displayName = "ImageSet";
|
||||
|
||||
render() {
|
||||
return <div className="ImageSet">
|
||||
<h2>{ this.props.imageSet.location } · { this.props.imageSet.description }</h2>
|
||||
<Grid
|
||||
images={ this.props.imageSet.images}
|
||||
onImageSelected={ this.props.onImageSelected }
|
||||
width={ this.props.width } />
|
||||
</div>;
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div className="ImageSet">
|
||||
<h2>
|
||||
{this.props.imageSet.location} · {this.props.imageSet.description}
|
||||
</h2>
|
||||
<Grid
|
||||
images={this.props.imageSet.images}
|
||||
onImageSelected={this.props.onImageSelected}
|
||||
width={this.props.width}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,39 +3,42 @@ import * as Model from "../model";
|
||||
import * as React from "react";
|
||||
|
||||
export interface Props {
|
||||
image: Model.Image;
|
||||
onClick: () => void;
|
||||
width: number;
|
||||
image: Model.Image;
|
||||
onClick: () => void;
|
||||
width: number;
|
||||
}
|
||||
|
||||
export class Picture extends React.PureComponent<Props, {}> {
|
||||
static displayName = "Picture";
|
||||
static displayName = "Picture";
|
||||
|
||||
render() {
|
||||
const src = `img/600/${this.props.image.src}`;
|
||||
return <img
|
||||
onClick={this.props.onClick}
|
||||
srcSet={this._srcset()}
|
||||
src={src}
|
||||
width={ this.props.width + "px" }
|
||||
/>;
|
||||
}
|
||||
render() {
|
||||
const src = `img/600/${this.props.image.src}`;
|
||||
return (
|
||||
<img
|
||||
onClick={this.props.onClick}
|
||||
srcSet={this._srcset()}
|
||||
src={src}
|
||||
width={this.props.width + "px"}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private _srcset = (): string => {
|
||||
const srcs: string[] = [];
|
||||
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;
|
||||
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;
|
||||
const scale = width / this.props.width;
|
||||
|
||||
if (scale >= 1) {
|
||||
srcs.push(`img/${size}/${this.props.image.src} ${scale}x`);
|
||||
}
|
||||
});
|
||||
if (scale >= 1) {
|
||||
srcs.push(`img/${size}/${this.props.image.src} ${scale}x`);
|
||||
}
|
||||
});
|
||||
|
||||
return srcs.join(",");
|
||||
}
|
||||
return srcs.join(",");
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,84 +7,88 @@ import * as React from "react";
|
||||
export interface Props {}
|
||||
|
||||
export interface State {
|
||||
data?: Model.Data | null;
|
||||
selectedImage?: Model.Image | null;
|
||||
width: number;
|
||||
data?: Model.Data | null;
|
||||
selectedImage?: Model.Image | null;
|
||||
width: number;
|
||||
}
|
||||
|
||||
export class Root extends React.PureComponent<Props, State> {
|
||||
static displayName = "Root";
|
||||
static displayName = "Root";
|
||||
|
||||
state: State = {
|
||||
width: window.innerWidth
|
||||
}
|
||||
state: State = {
|
||||
width: window.innerWidth
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
window.fetch(Model.URL)
|
||||
.then(data => data.json())
|
||||
.then(json => this.setState({ data: json }))
|
||||
.then(this._loadHash)
|
||||
.catch(e => console.error("Error fetching data", e));
|
||||
componentDidMount() {
|
||||
window
|
||||
.fetch(Model.URL)
|
||||
.then(data => data.json())
|
||||
.then(json => this.setState({ data: json }))
|
||||
.then(this._loadHash)
|
||||
.catch(e => console.error("Error fetching data", e));
|
||||
|
||||
window.onresize = () => {
|
||||
this.setState({ width: window.innerWidth });
|
||||
window.onresize = () => {
|
||||
this.setState({ width: window.innerWidth });
|
||||
};
|
||||
|
||||
window.onpopstate = this._loadHash;
|
||||
}
|
||||
|
||||
render() {
|
||||
const imageSets = this.state.data
|
||||
? this.state.data.sets.map(set => (
|
||||
<ImageSet
|
||||
key={set.location + set.description}
|
||||
imageSet={set}
|
||||
onImageSelected={this._onImageSelected}
|
||||
width={this.state.width}
|
||||
/>
|
||||
))
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div className="Root">
|
||||
{this._bigPicture()}
|
||||
<h1>Ski</h1>
|
||||
{imageSets}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private _bigPicture = () =>
|
||||
this.state.selectedImage ? (
|
||||
<BigPicture
|
||||
image={this.state.selectedImage}
|
||||
onClose={this._showGrid}
|
||||
width={this.state.width}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
private _loadHash = () => {
|
||||
if (window.location.hash.length > 0 && this.state.data) {
|
||||
const src = window.location.hash.slice(1);
|
||||
let selectedImage: Model.Image | null = null;
|
||||
|
||||
this.state.data.sets.forEach(set => {
|
||||
const image = set.images.find(image => image.src === src);
|
||||
if (image) {
|
||||
selectedImage = image;
|
||||
}
|
||||
});
|
||||
|
||||
window.onpopstate = this._loadHash;
|
||||
|
||||
this.setState({ selectedImage: selectedImage });
|
||||
} else {
|
||||
this.setState({ selectedImage: null });
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const imageSets = this.state.data
|
||||
? this.state.data.sets.map(set =>
|
||||
<ImageSet
|
||||
key={set.location + set.description}
|
||||
imageSet={set}
|
||||
onImageSelected={this._onImageSelected}
|
||||
width={this.state.width} />
|
||||
)
|
||||
: null;
|
||||
private _onImageSelected = (img: Model.Image) => {
|
||||
this.setState({ selectedImage: img });
|
||||
window.history.pushState(null, "", `#${img.src}`);
|
||||
};
|
||||
|
||||
return <div className="Root">
|
||||
{ this._bigPicture() }
|
||||
<h1>Ski</h1>
|
||||
{ imageSets }
|
||||
</div>;
|
||||
}
|
||||
|
||||
private _bigPicture = () =>
|
||||
this.state.selectedImage
|
||||
? <BigPicture
|
||||
image={this.state.selectedImage}
|
||||
onClose={this._showGrid}
|
||||
width={this.state.width} />
|
||||
: null
|
||||
|
||||
private _loadHash = () => {
|
||||
if (window.location.hash.length > 0 && this.state.data) {
|
||||
const src = window.location.hash.slice(1);
|
||||
let selectedImage: Model.Image | null = null;
|
||||
|
||||
this.state.data.sets.forEach(set => {
|
||||
const image = set.images.find(image => image.src === src);
|
||||
if (image) {
|
||||
selectedImage = image;
|
||||
}
|
||||
});
|
||||
|
||||
this.setState({ selectedImage: selectedImage });
|
||||
} else {
|
||||
this.setState({ selectedImage: null });
|
||||
}
|
||||
}
|
||||
|
||||
private _onImageSelected = (img: Model.Image) => {
|
||||
this.setState({ selectedImage: img });
|
||||
window.history.pushState(null, "", `#${img.src}`);
|
||||
}
|
||||
|
||||
private _showGrid = () => {
|
||||
this.setState({ selectedImage: null });
|
||||
window.history.pushState(null, "", "#");
|
||||
}
|
||||
private _showGrid = () => {
|
||||
this.setState({ selectedImage: null });
|
||||
window.history.pushState(null, "", "#");
|
||||
};
|
||||
}
|
||||
|
||||
14
src/model.ts
14
src/model.ts
@@ -2,17 +2,17 @@ export const SIZES = [1600, 1200, 800, 600, 400, 200];
|
||||
export const URL = "img/data.json";
|
||||
|
||||
export interface Data {
|
||||
sets: ImageSet[]
|
||||
sets: ImageSet[];
|
||||
}
|
||||
|
||||
export interface ImageSet {
|
||||
location: string;
|
||||
description: string;
|
||||
images: Image[]
|
||||
location: string;
|
||||
description: string;
|
||||
images: Image[];
|
||||
}
|
||||
|
||||
export interface Image {
|
||||
src: string;
|
||||
height: number;
|
||||
width: number;
|
||||
src: string;
|
||||
height: number;
|
||||
width: number;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user