big picture
This commit is contained in:
39
site.css
39
site.css
@@ -30,3 +30,42 @@ h1 {
|
|||||||
.Grid img {
|
.Grid img {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.BigPicture {
|
||||||
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
left: 0;
|
||||||
|
padding: 30px;
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BigPicture-image {
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: contain;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BigPicture-footer {
|
||||||
|
align-self: center;
|
||||||
|
display: flex;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 30px;
|
||||||
|
max-width: 200px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BigPicture-footerLink {
|
||||||
|
color: #69c;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BigPicture-footerLink:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|||||||
38
src/components/big_picture.tsx
Normal file
38
src/components/big_picture.tsx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import * as Model from "../model";
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
src: string;
|
||||||
|
image: Model.Image;
|
||||||
|
onClose: () => void;
|
||||||
|
width: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BigPicture extends React.PureComponent<Props, {}> {
|
||||||
|
static displayName = "BigPicture";
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const src = `img/1600/${this.props.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.src}`}
|
||||||
|
target="_blank">
|
||||||
|
Download
|
||||||
|
</a>
|
||||||
|
<span className="BigPicture-footerLink"
|
||||||
|
onClick={this.props.onClose}
|
||||||
|
tabIndex={1} >
|
||||||
|
Close
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,6 @@ import * as React from "react";
|
|||||||
export interface Props {
|
export interface Props {
|
||||||
images: Model.Images;
|
images: Model.Images;
|
||||||
onImageSelected: (key: string) => void;
|
onImageSelected: (key: string) => void;
|
||||||
selectedImage: string | null;
|
|
||||||
width: number;
|
width: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +51,6 @@ export class Grid extends React.PureComponent<Props, {}> {
|
|||||||
return <Picture
|
return <Picture
|
||||||
image={image}
|
image={image}
|
||||||
onClick={() => this.props.onImageSelected(key)}
|
onClick={() => this.props.onImageSelected(key)}
|
||||||
selected={this.props.selectedImage === key}
|
|
||||||
src={key}
|
src={key}
|
||||||
key={key}
|
key={key}
|
||||||
width={image.width/image.height * scale}
|
width={image.width/image.height * scale}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ export interface Props {
|
|||||||
src: string;
|
src: string;
|
||||||
image: Model.Image;
|
image: Model.Image;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
selected?: boolean;
|
|
||||||
width: number;
|
width: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,11 +15,10 @@ export class Picture extends React.PureComponent<Props, {}> {
|
|||||||
render() {
|
render() {
|
||||||
const src = `img/600/${this.props.src}`;
|
const src = `img/600/${this.props.src}`;
|
||||||
return <img
|
return <img
|
||||||
className={ this.props.selected ? "Picture-selected" : ""}
|
|
||||||
onClick={this.props.onClick}
|
onClick={this.props.onClick}
|
||||||
srcSet={this._srcset()}
|
srcSet={this._srcset()}
|
||||||
src={src}
|
src={src}
|
||||||
width={ this.props.selected ? "100%" : this.props.width + "px" }
|
width={ this.props.width + "px" }
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { BigPicture } from "./big_picture";
|
||||||
import { Grid } from "./grid";
|
import { Grid } from "./grid";
|
||||||
import * as Model from "../model";
|
import * as Model from "../model";
|
||||||
|
|
||||||
@@ -7,16 +8,15 @@ export interface Props {}
|
|||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
images: Model.Images;
|
images: Model.Images;
|
||||||
selectedIamge?: string | null;
|
selectedImage?: string | null;
|
||||||
width: number;
|
width: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Root extends React.PureComponent<Props, State> {
|
export class Root extends React.PureComponent<Props, State> {
|
||||||
static displayName = "Root";
|
static displayName = "Root";
|
||||||
|
|
||||||
state = {
|
state: State = {
|
||||||
images: {},
|
images: {},
|
||||||
selectedImage: null,
|
|
||||||
width: window.innerWidth
|
width: window.innerWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,24 +29,52 @@ export class Root extends React.PureComponent<Props, State> {
|
|||||||
window.onresize = () => {
|
window.onresize = () => {
|
||||||
this.setState({ width: window.innerWidth });
|
this.setState({ width: window.innerWidth });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.onpopstate = this._loadHash;
|
||||||
|
|
||||||
|
this._loadHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <div className="Root">
|
return <div className="Root">
|
||||||
<h1>Ski</h1>
|
<h1>Ski</h1>
|
||||||
<hr />
|
<hr />
|
||||||
|
{ this._bigPicture() }
|
||||||
<Grid
|
<Grid
|
||||||
images={ this.state.images }
|
images={ this.state.images }
|
||||||
onImageSelected={ this._onImageSelected }
|
onImageSelected={ this._onImageSelected }
|
||||||
selectedImage={ this.state.selectedImage }
|
|
||||||
width={ this.state.width } />
|
width={ this.state.width } />
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _bigPicture = () => {
|
||||||
|
if (this.state.selectedImage && this.state.images[this.state.selectedImage]) {
|
||||||
|
return <BigPicture
|
||||||
|
image={this.state.images[this.state.selectedImage]}
|
||||||
|
src={this.state.selectedImage}
|
||||||
|
onClose={this._showGrid}
|
||||||
|
width={this.state.width}
|
||||||
|
/>
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _loadHash = () => {
|
||||||
|
if (window.location.hash.length > 0) {
|
||||||
|
this.setState({ selectedImage: window.location.hash.slice(1) });
|
||||||
|
} else {
|
||||||
|
this.setState({ selectedImage: null });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _onImageSelected = (key: string) => {
|
private _onImageSelected = (key: string) => {
|
||||||
this.setState(state => ({
|
this.setState({ selectedImage: key });
|
||||||
...state,
|
window.history.pushState(null, "", `#${key}`);
|
||||||
selectedImage: key
|
}
|
||||||
}));
|
|
||||||
|
private _showGrid = () => {
|
||||||
|
this.setState({ selectedImage: null });
|
||||||
|
window.history.pushState(null, "", "#");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user