rewrote site with react
@ -3,6 +3,7 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"cors": "^2.8.5",
|
||||
"node-sass": "^4.13.1",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
|
36
server/app.js
Normal file
@ -0,0 +1,36 @@
|
||||
const express = require('express')
|
||||
const cors = require('cors')
|
||||
const bodyParser = require('body-parser')
|
||||
const fs = require('fs')
|
||||
|
||||
const app = express()
|
||||
const port = 8000
|
||||
|
||||
app.use(cors())
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
fs.readdir('./assets/', (err, items) => {
|
||||
result = items.map(el => 'image/' + el)
|
||||
const pageSize = req.query.size || 3;
|
||||
const pagesAmount = Math.ceil(items.length / pageSize );
|
||||
const page = (req.query.page > pagesAmount) ? pagesAmount : req.query.page || 1;
|
||||
console.log(`Page=${page}, server acessed`)
|
||||
res.json({
|
||||
"page": page,
|
||||
"pagesAmount": pagesAmount,
|
||||
"list": result.slice(page * pageSize - pageSize, page * pageSize),
|
||||
})
|
||||
})
|
||||
})
|
||||
app.get('/image/:name.:subname', (req, res) => {
|
||||
res.sendFile(__dirname + '/assets/' + req.params.name + '.' + req.params.subname, (err) => {
|
||||
console.log(__dirname + '/assets/' + req.params.name + '.' + req.params.subname)
|
||||
if (err) {
|
||||
next(err)
|
||||
} else {
|
||||
console.log('Sent:', req.query.path)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
|
BIN
server/assets/1-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 3.7 MiB |
BIN
server/assets/10-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.2 MiB |
BIN
server/assets/11-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.5 MiB |
BIN
server/assets/12-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 3.1 MiB |
BIN
server/assets/13-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 3.6 MiB |
BIN
server/assets/14-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.4 MiB |
BIN
server/assets/15-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.8 MiB |
BIN
server/assets/16-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.4 MiB |
BIN
server/assets/17-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 3.8 MiB |
BIN
server/assets/18-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 3.7 MiB |
BIN
server/assets/19-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.8 MiB |
BIN
server/assets/2-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.5 MiB |
BIN
server/assets/20-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.0 MiB |
BIN
server/assets/21-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.4 MiB |
BIN
server/assets/22-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 3.7 MiB |
BIN
server/assets/23-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.0 MiB |
BIN
server/assets/24-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.9 MiB |
BIN
server/assets/25-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 3.9 MiB |
BIN
server/assets/26-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.4 MiB |
BIN
server/assets/3-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.7 MiB |
BIN
server/assets/4-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.4 MiB |
BIN
server/assets/5-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.7 MiB |
BIN
server/assets/6-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.1 MiB |
BIN
server/assets/7-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 4.3 MiB |
BIN
server/assets/8-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 3.7 MiB |
BIN
server/assets/9-early-morning-walk.jpeg
Normal file
After Width: | Height: | Size: 3.6 MiB |
@ -8,10 +8,12 @@ import {
|
||||
Navbar,
|
||||
Home,
|
||||
Gallery,
|
||||
Footer,
|
||||
} from './components'
|
||||
import './app.css';
|
||||
import './app.scss';
|
||||
|
||||
const App = () => {
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Router>
|
||||
<Navbar />
|
||||
@ -23,6 +25,8 @@ export default function App() {
|
||||
<Home />
|
||||
</Route>
|
||||
</Switch>
|
||||
<Footer />
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
export default App;
|
@ -1,9 +1,11 @@
|
||||
@import url('https://fonts.googleapis.com/css?family=Assistant|Kaushan+Script&display=swap');
|
||||
#root {
|
||||
padding-top: 10vh;
|
||||
}
|
||||
|
||||
a, p, span {
|
||||
font-family: 'Assistant', sans-serif;
|
||||
font-size: 3vh;
|
||||
font-weight: 300;
|
||||
color: var(--text-color);
|
||||
}
|
||||
body {
|
||||
background-color: var(--background-color);
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
import Navbar from './components/Navbar';
|
||||
import Home from './components/Home';
|
||||
import Gallery from './components/Gallety'
|
||||
import { GalleryView as Gallery } from './components/GalleryView'
|
||||
import Footer from './components/Footer'
|
||||
|
||||
export {
|
||||
Navbar,
|
||||
Home,
|
||||
Gallery
|
||||
Gallery,
|
||||
Footer
|
||||
};
|
13
src/components/Footer.js
Normal file
@ -0,0 +1,13 @@
|
||||
import React from 'react'
|
||||
import './footer.scss'
|
||||
import { ReactComponent as Telegram} from './telegram.svg'
|
||||
|
||||
const Footer = () => {
|
||||
return (
|
||||
<footer>
|
||||
<Telegram className="telegram" />
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
|
||||
export default Footer;
|
36
src/components/Gallery.js
Normal file
@ -0,0 +1,36 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import GalleryItem from "./GalleryItem";
|
||||
import './gallery.scss';
|
||||
|
||||
const GalleryList = (json) => {
|
||||
let result = [];
|
||||
let key = 0;
|
||||
for (const el of json) {
|
||||
result.push(
|
||||
<GalleryItem key={key++} src={el} />
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const Gallery = props => {
|
||||
const [galleryData, setGalleryData] = useState([]);
|
||||
const size = (props.type === "galleryList") ? 4 : 9;
|
||||
|
||||
useEffect( () => {
|
||||
async function fetchData() {
|
||||
const res = await fetch(`http://localhost:8000/?size=${size}`);
|
||||
const json = await res.json();
|
||||
setGalleryData(json.list);
|
||||
}
|
||||
fetchData();
|
||||
}, [size]);
|
||||
|
||||
return (
|
||||
<div className={props.type}>
|
||||
{GalleryList(galleryData)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Gallery;
|
18
src/components/GalleryItem.js
Normal file
@ -0,0 +1,18 @@
|
||||
import React, { useState } from 'react';
|
||||
import ViewBox from './ViewBox'
|
||||
import './GalleryItem.scss';
|
||||
|
||||
const GalleryItem = props => {
|
||||
const [showViewBox, setShowViewbox] = useState(false);
|
||||
const src = 'http://localhost:8000/' + props.src;
|
||||
|
||||
return (
|
||||
<div className="galleryItem" onClick={ () => setShowViewbox(true) }>
|
||||
<img alt="My shots" src={src} />
|
||||
|
||||
{showViewBox && <ViewBox src={src} click={setShowViewbox} /> }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default GalleryItem;
|
14
src/components/GalleryItem.scss
Normal file
@ -0,0 +1,14 @@
|
||||
.galleryItem {
|
||||
margin-bottom: 3vh;
|
||||
|
||||
& > img {
|
||||
z-index: 5;
|
||||
max-width: 100%;
|
||||
max-height: 75vh;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
filter: contrast(75%) brightness(120%);
|
||||
}
|
||||
}
|
||||
}
|
14
src/components/GalleryView.js
Normal file
@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import Gallery from './Gallery'
|
||||
import './galleryView.scss';
|
||||
|
||||
const GalleryView = () => {
|
||||
|
||||
return (
|
||||
<div className="galleryView">
|
||||
<h1>Gallery</h1>
|
||||
<Gallery type="galleryGrid" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export { GalleryView };
|
@ -1,10 +0,0 @@
|
||||
import React from 'react';
|
||||
import './gallery.css';
|
||||
|
||||
export default function Gallery () {
|
||||
return (
|
||||
<div>
|
||||
Gallery
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,10 +1,19 @@
|
||||
import React from 'react';
|
||||
import './home.css';
|
||||
import Gallery from './Gallery'
|
||||
import './home.scss';
|
||||
|
||||
export default function Home () {
|
||||
const Home = () => {
|
||||
return (
|
||||
<div>
|
||||
Home
|
||||
<header>
|
||||
<h1>Dmitriy</h1>
|
||||
<p>Welcome to my personal site!</p>
|
||||
</header>
|
||||
<main>
|
||||
<p>I'm Dmitriy Shishkov — photographer, programmer, filmmaker and writer. Here you can see some of my works. I'll upload more soon.</p>
|
||||
<Gallery type="galleryList" />
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default Home;
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import './navbar.scss'
|
||||
import { ReactComponent as Logo } from './logo.svg'
|
||||
export default function Navbar () {
|
||||
const Navbar = () => {
|
||||
return (
|
||||
<nav>
|
||||
<Link to="/">
|
||||
@ -14,4 +14,5 @@ export default function Navbar () {
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default Navbar;
|
13
src/components/ViewBox.js
Normal file
@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import './viewBox.scss';
|
||||
|
||||
const ViewBox = props => {
|
||||
return (
|
||||
<div className="viewBox" >
|
||||
<img alt="Full" src={props.src} onClick={() => {
|
||||
setTimeout(() => props.click(false), 100);
|
||||
}} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default ViewBox;
|
10
src/components/footer.scss
Normal file
@ -0,0 +1,10 @@
|
||||
footer {
|
||||
width: 100vw;
|
||||
min-height: 25vh;
|
||||
display: flex;
|
||||
|
||||
.telegram {
|
||||
fill: #2a9fd9;
|
||||
height: 10vh;
|
||||
}
|
||||
}
|
17
src/components/gallery.scss
Normal file
@ -0,0 +1,17 @@
|
||||
.galleryGrid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-gap: 3vh;
|
||||
padding: 10vh 10vw;
|
||||
}
|
||||
.galleryList {
|
||||
width: 100%;
|
||||
|
||||
.galleryItem {
|
||||
max-width: 50vw;
|
||||
|
||||
&:nth-child(2n) {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
11
src/components/galleryView.scss
Normal file
@ -0,0 +1,11 @@
|
||||
.galleryView {
|
||||
h1 {
|
||||
grid-column: span 3;
|
||||
font-family: 'Kaushan Script', cursive;
|
||||
font-size: 10vh;
|
||||
text-align: center;
|
||||
padding-top: 10vh;
|
||||
padding-bottom: 7vh;
|
||||
color: var(--text-color);
|
||||
}
|
||||
}
|
BIN
src/components/header_bg.jpeg
Normal file
After Width: | Height: | Size: 4.5 MiB |
31
src/components/home.scss
Normal file
@ -0,0 +1,31 @@
|
||||
header {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
background-image: linear-gradient( rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1) ), url(./header_bg.jpeg);
|
||||
background-size: cover;
|
||||
background-position: bottom;
|
||||
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
|
||||
|
||||
h1 {
|
||||
font-family: 'Kaushan Script', cursive;
|
||||
font-size: 10vh;
|
||||
color: #ffffff;
|
||||
}
|
||||
p {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
main {
|
||||
padding: 15vmin;
|
||||
display: inline-block;
|
||||
|
||||
& > p {
|
||||
font-size: 5vh;
|
||||
margin-bottom: 15vmin;
|
||||
}
|
||||
}
|
@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 336 432"><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><rect fill='#282627' width="32" height="432"/><rect fill='#282627' x="54" width="32" height="432"/><path fill='#282627' d="M108,0V30.32c108.08,0,196,83.29,196,185.68S216.08,401.68,108,401.68V432c125.72,0,228-96.9,228-216S233.72,0,108,0Z"/><path fill='#282627' d="M271.88,219.79c0-85.6-73.52-155.26-163.88-155.26V94.85c72.72,0,131.88,56.05,131.88,124.94S180.72,344.73,108,344.73V375C198.36,375,271.88,305.39,271.88,219.79Z"/></g></g></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 336 432"><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><rect width="32" height="432"/><rect x="54" width="32" height="432"/><path d="M108,0V30.32c108.08,0,196,83.29,196,185.68S216.08,401.68,108,401.68V432c125.72,0,228-96.9,228-216S233.72,0,108,0Z"/><path d="M271.88,219.79c0-85.6-73.52-155.26-163.88-155.26V94.85c72.72,0,131.88,56.05,131.88,124.94S180.72,344.73,108,344.73V375C198.36,375,271.88,305.39,271.88,219.79Z"/></g></g></svg>
|
Before Width: | Height: | Size: 574 B After Width: | Height: | Size: 518 B |
@ -5,10 +5,16 @@ nav {
|
||||
display: flex;
|
||||
padding: 2vh 4vw;
|
||||
width: 100vw;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
|
||||
background-color: var(--background-color);
|
||||
z-index: 100;
|
||||
|
||||
&.showShadow {
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6vh;
|
||||
fill: var(--text-color);
|
||||
}
|
||||
|
||||
div {
|
||||
|
1
src/components/telegram.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"><path id="telegram-4" d="M12,0c-6.626,0 -12,5.372 -12,12c0,6.627 5.374,12 12,12c6.627,0 12,-5.373 12,-12c0,-6.628 -5.373,-12 -12,-12Zm3.224,17.871c0.188,0.133 0.43,0.166 0.646,0.085c0.215,-0.082 0.374,-0.267 0.422,-0.491c0.507,-2.382 1.737,-8.412 2.198,-10.578c0.035,-0.164 -0.023,-0.334 -0.151,-0.443c-0.129,-0.109 -0.307,-0.14 -0.465,-0.082c-2.446,0.906 -9.979,3.732 -13.058,4.871c-0.195,0.073 -0.322,0.26 -0.316,0.467c0.007,0.206 0.146,0.385 0.346,0.445c1.381,0.413 3.193,0.988 3.193,0.988c0,0 0.847,2.558 1.288,3.858c0.056,0.164 0.184,0.292 0.352,0.336c0.169,0.044 0.348,-0.002 0.474,-0.121c0.709,-0.669 1.805,-1.704 1.805,-1.704c0,0 2.084,1.527 3.266,2.369Zm-6.423,-5.062l0.98,3.231l0.218,-2.046c0,0 3.783,-3.413 5.941,-5.358c0.063,-0.057 0.071,-0.153 0.019,-0.22c-0.052,-0.067 -0.148,-0.083 -0.219,-0.037c-2.5,1.596 -6.939,4.43 -6.939,4.43Z"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
16
src/components/viewBox.scss
Normal file
@ -0,0 +1,16 @@
|
||||
.viewBox {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: var(--background-color);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
|
||||
img {
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './index.css';
|
||||
import './index.scss';
|
||||
import App from './App';
|
||||
import * as serviceWorker from './serviceWorker';
|
||||
|
||||
|
@ -1,5 +1,16 @@
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
--background-color: #ffffff;
|
||||
--text-color: #282627;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: inherit;
|
||||
margin: 0;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
*::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
@ -21,3 +32,11 @@ code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
--background-color: #1c1c1e;
|
||||
--text-color: #ffffff;
|
||||
}
|
||||
}
|
12
yarn.lock
@ -2975,6 +2975,14 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
|
||||
cors@^2.8.5:
|
||||
version "2.8.5"
|
||||
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
|
||||
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
|
||||
dependencies:
|
||||
object-assign "^4"
|
||||
vary "^1"
|
||||
|
||||
cosmiconfig@^5.0.0, cosmiconfig@^5.2.1:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
|
||||
@ -7110,7 +7118,7 @@ oauth-sign@~0.9.0:
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
|
||||
|
||||
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
@ -10526,7 +10534,7 @@ value-equal@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c"
|
||||
integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==
|
||||
|
||||
vary@~1.1.2:
|
||||
vary@^1, vary@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
|
||||
|