WIP React > Svelte
Put most of the developed design into Svelte
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<script context="module">
|
||||
import { api, site, continents, countries, locations, currentLocation } from '../store'
|
||||
import { apiEndpoints, site, continents, countries, locations } from '../store'
|
||||
|
||||
export async function preload (page, segment) {
|
||||
const res = await this.fetch(api.graphql, {
|
||||
export async function preload (page, session) {
|
||||
const request = await this.fetch(apiEndpoints.gql, {
|
||||
method: 'post',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ query: `{
|
||||
@@ -25,11 +25,8 @@
|
||||
id
|
||||
name
|
||||
slug
|
||||
continent { id name }
|
||||
flag {
|
||||
full_url
|
||||
title
|
||||
}
|
||||
flag { full_url title }
|
||||
continent { id }
|
||||
}
|
||||
}
|
||||
locations (filter: { status_eq: "published" }) {
|
||||
@@ -38,55 +35,42 @@
|
||||
name
|
||||
slug
|
||||
region
|
||||
country {
|
||||
name slug
|
||||
flag {
|
||||
full_url
|
||||
title
|
||||
}
|
||||
continent { id name }
|
||||
}
|
||||
country { id }
|
||||
description
|
||||
}
|
||||
}
|
||||
}`})
|
||||
})
|
||||
const data = await res.json()
|
||||
const result = await request.json()
|
||||
|
||||
// Set data into store
|
||||
continents.set(data.data.continents.data)
|
||||
countries.set(data.data.countries.data)
|
||||
locations.set(data.data.locations.data)
|
||||
site.set(data.data.site.data[0])
|
||||
site.set(result.data.site.data[0])
|
||||
continents.set(result.data.continents.data)
|
||||
countries.set(result.data.countries.data)
|
||||
locations.set(result.data.locations.data)
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Styles
|
||||
// import '../../node_modules/bulma/css/bulma.min.css'
|
||||
// import '../../node_modules/@fortawesome/fontawesome-free/css/all.min.css'
|
||||
|
||||
// Components
|
||||
import Footer from '../parts/Footer.svelte'
|
||||
// Manipulate countries data
|
||||
// Replace each countrie's continent by the database
|
||||
$countries.forEach(count => count.continent = $continents.find(cont => cont.id === count.continent.id))
|
||||
|
||||
// Manipulate continents data
|
||||
// Push each country to its continent
|
||||
$countries.forEach(country => {
|
||||
const continent = $continents.find(c => c.id === country.continent.id)
|
||||
const continent = $continents.find(cont => cont.id === country.continent.id)
|
||||
continent.countries = []
|
||||
if (!continent.countries.includes(country)) {
|
||||
continent.countries.push(country)
|
||||
}
|
||||
!continent.countries.includes(country) && continent.countries.push(country)
|
||||
})
|
||||
|
||||
// Manipulate locations data
|
||||
// Replace each location's country by the database
|
||||
$locations.forEach(loc => loc.country = $countries.find(cont => cont.id === loc.country.id))
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Houses Of - Beautiful houses of planet Earth</title>
|
||||
</svelte:head>
|
||||
|
||||
<style lang="scss" global>
|
||||
@import '../style/style.scss';
|
||||
@import "style/style.scss";
|
||||
</style>
|
||||
|
||||
<slot></slot>
|
||||
|
||||
<Footer />
|
||||
|
||||
@@ -1,14 +1,43 @@
|
||||
<script>
|
||||
import { fade, slide } from 'svelte/transition'
|
||||
import { site } from '../store'
|
||||
import Locations from '../components/Locations'
|
||||
import { site, currentLocation } from '../store'
|
||||
|
||||
// Components
|
||||
import Globe from '../molecules/InteractiveGlobe'
|
||||
import Footer from '../molecules/Footer'
|
||||
import Locations from '../organisms/Locations'
|
||||
|
||||
// Reset current location if existing
|
||||
$: if ($currentLocation) {
|
||||
currentLocation.set()
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Houses Of - Beautiful houses of planet Earth</title>
|
||||
</svelte:head>
|
||||
|
||||
<section class="hero is-medium is-danger has-text-centered">
|
||||
<section class="explore">
|
||||
<div class="wrap">
|
||||
<div class="explore__top">
|
||||
<a href="/" class="button-control button-control--pink">
|
||||
<img src="/img/icons/arrow-white.svg" alt="">
|
||||
</a>
|
||||
<h1 class="title-location">Houses <em>of the</em> World</h1>
|
||||
</div>
|
||||
|
||||
<div class="description">
|
||||
<p>{$site.explore_globe}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Globe />
|
||||
|
||||
<Locations />
|
||||
</section>
|
||||
|
||||
<Footer />
|
||||
|
||||
<!-- <section class="hero is-medium is-danger has-text-centered">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h1 class="title">Houses Of The World</h1>
|
||||
@@ -31,4 +60,4 @@
|
||||
|
||||
<Locations />
|
||||
</section>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
@@ -5,16 +5,70 @@
|
||||
|
||||
// Dependencies
|
||||
// import anime from 'animejs/lib/anime.es.js'
|
||||
// import * as basicScroll from 'basicscroll'
|
||||
|
||||
// Components
|
||||
import Locations from '../components/Locations'
|
||||
import Footer from '../parts/Footer'
|
||||
import Button from '../atoms/Button'
|
||||
import IconGlobeSmall from '../atoms/IconGlobeSmall'
|
||||
import IconGlobe from '../atoms/IconGlobe'
|
||||
import InteractiveGlobe from '../molecules/InteractiveGlobe'
|
||||
import Carousel from '../organisms/Carousel'
|
||||
import Locations from '../organisms/Locations'
|
||||
import Footer from '../molecules/Footer'
|
||||
|
||||
// Reset current location
|
||||
currentLocation.set(undefined)
|
||||
// Reset current location if existing
|
||||
$: if ($currentLocation) {
|
||||
currentLocation.set()
|
||||
}
|
||||
</script>
|
||||
|
||||
<section class="hero is-medium is-danger has-text-centered">
|
||||
<svelte:head>
|
||||
<title>Houses Of - Beautiful houses of planet Earth</title>
|
||||
</svelte:head>
|
||||
|
||||
<section class="intro">
|
||||
<h1 class="title-massive title-parallax">Houses</h1>
|
||||
<!-- <MassiveTitle
|
||||
text="Houses"
|
||||
scrollFrom="0" scrollTo={window.innerHeight * 0.6}
|
||||
effectFrom="-5vw" effectTo="-20vw"
|
||||
/> -->
|
||||
|
||||
<div class="wrap">
|
||||
<div class="description">
|
||||
<p>{$site.description}</p>
|
||||
|
||||
<Button href="/choose" type="button" text="Explore locations">
|
||||
<IconGlobeSmall width="22" color="#666" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Carousel />
|
||||
</section>
|
||||
|
||||
<section class="explore explore--homepage">
|
||||
<p class="of">of</p>
|
||||
|
||||
<div class="description">
|
||||
<p>{$site.explore_list}</p>
|
||||
</div>
|
||||
|
||||
<InteractiveGlobe />
|
||||
|
||||
<!-- <MassiveTitle
|
||||
text="World"
|
||||
scrollFrom="0" scrollTo={window.innerHeight * 0.6}
|
||||
effectFrom="-5vw" effectTo="-20vw"
|
||||
/> -->
|
||||
<h1 class="title-massive title-parallax">World</h1>
|
||||
|
||||
<Locations />
|
||||
</section>
|
||||
|
||||
<Footer />
|
||||
|
||||
<!-- <section class="hero is-medium is-danger has-text-centered">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h1 class="title">Houses Of</h1>
|
||||
@@ -26,6 +80,10 @@
|
||||
<div class="section">
|
||||
<div class="container">
|
||||
<h2 class="title is-4">Choose on globe</h2>
|
||||
|
||||
<IconGlobeSmall width="14" color="red" />
|
||||
<IconGlobe />
|
||||
|
||||
<div class="content">
|
||||
<p>{$site.explore_globe}</p>
|
||||
<p>[globe]</p>
|
||||
@@ -40,4 +98,4 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
<!-- <Footer /> -->
|
||||
|
||||
@@ -1,74 +1,165 @@
|
||||
<script context="module">
|
||||
// Svelte
|
||||
import { api, site, locations, currentLocation } from '../../../store'
|
||||
import { apiEndpoints, site, locations, currentLocation } from '../../../store'
|
||||
import { stores } from '@sapper/app'
|
||||
|
||||
// Preload
|
||||
// Preload data
|
||||
export async function preload (page, session) {
|
||||
const photos = await this.fetch(`${api.rest}/items/photos?fields=id,name,date,slug,image.data,created_on,modified_on&filter[location.slug][rlike]=%${page.params.location}%&sort=-created_on,name`)
|
||||
const photosData = await photos.json()
|
||||
|
||||
return {
|
||||
photos: photosData.data
|
||||
// Load photos
|
||||
const req = await this.fetch(`${apiEndpoints.rest}/items/photos?fields=id,name,date,slug,image.data,created_on,modified_on&filter[location.slug][rlike]=%${page.params.location}%&sort=-created_on,name`)
|
||||
const photos = await req.json()
|
||||
if (req.status === 200) {
|
||||
return { photos: photos.data }
|
||||
}
|
||||
this.error(404, 'Not found')
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Svelte
|
||||
import { fade, slide } from 'svelte/transition'
|
||||
import { stores } from '@sapper/app'
|
||||
const { page } = stores()
|
||||
export let photos
|
||||
|
||||
// Dependencies
|
||||
import dayjs from 'dayjs'
|
||||
import advancedFormat from 'dayjs/plugin/advancedFormat'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
|
||||
// Components
|
||||
import IconGlobe from '../../../atoms/iconGlobe'
|
||||
import IconGlobeSmall from '../../../atoms/iconGlobeSmall'
|
||||
import Cursor from '../../../atoms/Cursor'
|
||||
import Photo from '../../../molecules/Photo'
|
||||
import Switcher from '../../../molecules/Switcher'
|
||||
import Footer from '../../../molecules/Footer'
|
||||
|
||||
// Props
|
||||
export let photos
|
||||
|
||||
// Setup
|
||||
const { page } = stores()
|
||||
dayjs.extend(advancedFormat)
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
// Components
|
||||
import Photo from '../../../components/Photo'
|
||||
import SwitcherSide from '../../../components/SwitcherSide'
|
||||
|
||||
// Update current location
|
||||
currentLocation.set({
|
||||
location: $locations.find(location => location.slug === $page.params.location),
|
||||
photos: photos
|
||||
})
|
||||
const location = $locations.find(loc => loc.slug === $page.params.location)
|
||||
currentLocation.set({ location, photos })
|
||||
|
||||
// Define things
|
||||
const locationFull = `${$currentLocation.location.name}, ${$currentLocation.location.country.name}`
|
||||
const dateUpdated = (photos.length) ? {
|
||||
full: dayjs(photos[0].modified_on).format('MMM Do, YYYY'),
|
||||
relative: dayjs().to(dayjs(photos[0].modified_on))
|
||||
} : undefined
|
||||
const lastUpdated = (photos.length) ? ((dayjs(photos[0].modified_on).isBefore(dayjs().subtract(1, 'M'))) ? dateUpdated.full : dateUpdated.relative) : undefined
|
||||
// Define full location
|
||||
const locationFull = `${location.name}, ${location.country.name}`
|
||||
|
||||
// Define dates
|
||||
const dateUpdatedFull = photos.length ? dayjs(photos[0].modified_on).format('MMM Do, YYYY') : ''
|
||||
const dateUpdatedRelative = photos.length ? dayjs().to(dayjs(photos[0].modified_on)) : ''
|
||||
const lastUpdated = photos.length ? (dayjs(photos[0].modified_on).isBefore(dayjs().subtract(1, 'M'))) ? dateUpdatedFull : dateUpdatedRelative : ''
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Houses Of - Beautiful houses of {locationFull}</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="section container">
|
||||
<section class="place">
|
||||
<div class="place__title">
|
||||
<h1 class="title-location title-location--big">
|
||||
<span class="top">Houses <em>of</em></span>
|
||||
<span class="bottom">{location.name}</span>
|
||||
</h1>
|
||||
|
||||
<a href="/choose" class="button-control button-control--big button-control--dashed">
|
||||
<span class="center">
|
||||
<IconGlobe width="44" color="#fff" />
|
||||
<span>Change</span>
|
||||
</span>
|
||||
<svg>
|
||||
<circle cx="50%" cy="50%" r="43%"></circle>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="wrap place__description--wrap">
|
||||
<div class="place__description">
|
||||
<div class="wrapper">
|
||||
<p>{$site.description}</p>
|
||||
<p>
|
||||
Houses Of
|
||||
<a href="/choose" class="link-change">
|
||||
{location.name}
|
||||
<span class="icon">
|
||||
<IconGlobeSmall width="14" color="#999" />
|
||||
</span>
|
||||
</a>
|
||||
{location.description}
|
||||
</p>
|
||||
<p class="updated style-caps">
|
||||
<strong>Updated</strong>
|
||||
<time datetime={dateUpdatedFull} title={dateUpdatedFull}>{lastUpdated}</time>
|
||||
</p>
|
||||
|
||||
<div class="toggle">
|
||||
<button on:click class="active">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="19" height="17" viewBox="0 0 19 17">
|
||||
<path fill="#FF6C89" fillRule="evenodd" d="M39,30 L39,33 L24,33 L24,30 L39,30 Z M43,23 L43,26 L28,26 L28,23 L43,23 Z M39,16 L39,19 L24,19 L24,16 L39,16 Z" transform="translate(-24 -16)" />
|
||||
</svg>
|
||||
<span>List</span>
|
||||
</button>
|
||||
<button on:click>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" viewBox="0 0 18 20">
|
||||
<path fill="#FF6C89" fillRule="evenodd" d="M63,27 L63,34 L56,34 L56,27 L63,27 Z M52,25 L52,32 L45,32 L45,25 L52,25 Z M63,16 L63,23 L56,23 L56,16 L63,16 Z M52,14 L52,21 L45,21 L45,14 L52,14 Z" transform="translate(-45 -14)"/>
|
||||
</svg>
|
||||
<span>Grid</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="photos photos--list">
|
||||
<aside class="photos__side">
|
||||
<div class="sticky">
|
||||
<Switcher type="switcher--side" />
|
||||
<p class="updated style-caps">
|
||||
<strong>Updated</strong>
|
||||
<time datetime={dateUpdatedFull} title={dateUpdatedFull}>{lastUpdated}</time>
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<Cursor type="zoom" />
|
||||
|
||||
<div class="wrap">
|
||||
{#each photos as photo, index}
|
||||
<Photo {photo} index={index + 1} />
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<section class="pagination">
|
||||
<button>
|
||||
<div class="pagination__page">
|
||||
<p><span>page</span> 1/3</p>
|
||||
</div>
|
||||
<p class="style-caps pagination__caption">See more photos</p>
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<Footer />
|
||||
</section>
|
||||
|
||||
<!-- <div class="section container">
|
||||
<div class="nav content">
|
||||
<SwitcherSide />
|
||||
<Switcher />
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h1 class="title is-2">{locationFull}</h1>
|
||||
{#if $currentLocation && $currentLocation.location.description}
|
||||
{#if location && location.description}
|
||||
<p>
|
||||
{$site.description}<br>
|
||||
Houses Of <a href="/choose">{$currentLocation.location.name}</a> {$currentLocation.location.description}
|
||||
Houses Of <a href="/choose">{location.name}</a> {location.description}
|
||||
</p>
|
||||
{/if}
|
||||
{#if photos.length > 0}
|
||||
<p><strong>Updated</strong> <time title="{dateUpdated && dateUpdated.full}">{lastUpdated}</time></p>
|
||||
{#if photos.length}
|
||||
<p><strong>Updated</strong> <time datetime={dateUpdatedFull} title={dateUpdatedFull}>{lastUpdated}</time></p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if photos.length > 0}
|
||||
{#if photos.length}
|
||||
<div class="columns is-multiline">
|
||||
{#each photos as photo, index}
|
||||
<div class="column is-one-third">
|
||||
@@ -83,4 +174,4 @@
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
<script context="module">
|
||||
// Svelte
|
||||
import { api, locations, currentLocation } from '../../../../store'
|
||||
import { apiEndpoints, locations, currentLocation } from '../../../../store'
|
||||
import { stores } from '@sapper/app'
|
||||
|
||||
// Define to preload data or load the store
|
||||
// Define either to preload data or use the store
|
||||
let preloaded
|
||||
currentLocation.subscribe(store => {
|
||||
preloaded = (store) ? store : undefined
|
||||
})
|
||||
currentLocation.subscribe(store => preloaded = store ? store : undefined)
|
||||
|
||||
// Sapper preload data
|
||||
// Preload data
|
||||
export async function preload (page, session) {
|
||||
if (preloaded === undefined) {
|
||||
const photos = await this.fetch(`${api.rest}/items/photos?fields=id,name,slug,image.data,created_on&filter[location.slug][rlike]=%${page.params.location}%`)
|
||||
const photosData = await photos.json()
|
||||
// Load the photos if not loaded
|
||||
if (!preloaded) {
|
||||
const req = await this.fetch(`${apiEndpoints.rest}/items/photos?fields=id,name,slug,image.data,created_on&filter[location.slug][rlike]=%${page.params.location}%`)
|
||||
const photos = await req.json()
|
||||
return {
|
||||
photos: photosData.data
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
photos: preloaded.photos
|
||||
photos: photos.data
|
||||
}
|
||||
}
|
||||
// Use the store otherwise
|
||||
else return {
|
||||
photos: preloaded.photos
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { stores } from '@sapper/app'
|
||||
const { page, session, preloading } = stores()
|
||||
|
||||
// Dependencies
|
||||
@@ -33,18 +31,15 @@
|
||||
import advancedFormat from 'dayjs/plugin/advancedFormat'
|
||||
dayjs.extend(advancedFormat)
|
||||
|
||||
// Props and variables
|
||||
export let photos
|
||||
let currentIndex
|
||||
let indexFormated
|
||||
let viewerPhotos
|
||||
|
||||
// Define current location
|
||||
if ($currentLocation === undefined) {
|
||||
currentLocation.set({
|
||||
location: $locations.find(location => location.slug === $page.params.location),
|
||||
photos: photos
|
||||
})
|
||||
}
|
||||
const location = $locations.find(loc => loc.slug === $page.params.location)
|
||||
$currentLocation == undefined && currentLocation.set({ location, photos })
|
||||
|
||||
// Set current photo, index and siblings
|
||||
const setCurrentPhotos = () => {
|
||||
@@ -53,9 +48,9 @@
|
||||
indexFormated = (currentIndex < 10) ? '0' + (currentIndex + 1) : currentIndex + 1
|
||||
viewerPhotos = {
|
||||
current: photos[currentIndex],
|
||||
// Last photo if first, otherwise index-1
|
||||
// Last photo if first, otherwise index - 1
|
||||
prev: (currentIndex === 0) ? photos[photos.length - 1] : photos[currentIndex - 1],
|
||||
// First photo if last, otherwise index+1
|
||||
// First photo if last, otherwise index + 1
|
||||
next: (currentIndex === photos.length - 1) ? photos[0] : photos[currentIndex + 1]
|
||||
}
|
||||
}
|
||||
@@ -67,9 +62,9 @@
|
||||
}
|
||||
})
|
||||
|
||||
// Define things
|
||||
const locationFull = `${$currentLocation.location.name}, ${$currentLocation.location.country.name}`
|
||||
const path = `/viewer/${$currentLocation.location.country.slug}/${$currentLocation.location.slug}/`
|
||||
// Define values
|
||||
const locationFull = `${location.name}, ${location.country.name}`
|
||||
const path = `/viewer/${location.country.slug}/${location.slug}/`
|
||||
|
||||
// Get thumbnail
|
||||
const getThumb = (photo, size) => {
|
||||
@@ -99,12 +94,12 @@
|
||||
<div class="container">
|
||||
<div class="nav content">
|
||||
<a href="/choose" class="button is-info" id="photo_close">Change location</a>
|
||||
<a href="/location/{$currentLocation.location.country.slug}/{$currentLocation.location.slug}" class="button is-dark" id="photo_close">Close</a>
|
||||
<a href="/location/{location.country.slug}/{location.slug}" class="button is-dark" id="photo_close">Close</a>
|
||||
</div>
|
||||
|
||||
<div class="photo">
|
||||
<div class="image">
|
||||
<img src="{getThumb(viewerPhotos.current, 'large')}" srcset="{getThumb(viewerPhotos.current, 'large')} 1x, {getThumb(viewerPhotos.current, 'large-2x')} 2x" alt="{viewerPhotos.current.name}">
|
||||
<img src={getThumb(viewerPhotos.current, 'large')} srcset="{getThumb(viewerPhotos.current, 'large')} 1x, {getThumb(viewerPhotos.current, 'large-2x')} 2x" alt="viewerPhotos.current.name">
|
||||
</div>
|
||||
<div class="details content">
|
||||
<strong class="is-size-5">{viewerPhotos.current.name}</strong> <br>
|
||||
@@ -117,10 +112,10 @@
|
||||
<div class="section">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<a href="{path + viewerPhotos.prev.slug}" id="photo_prev">
|
||||
<a href={path + viewerPhotos.prev.slug} id="photo_prev">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<img src="{getThumb(viewerPhotos.prev, 'thumbnail')}" alt="{viewerPhotos.prev.name}" width="200">
|
||||
<img src={getThumb(viewerPhotos.prev, 'thumbnail')} alt={viewerPhotos.prev.name} width="200">
|
||||
</div>
|
||||
<div class="media-content content">
|
||||
<strong class="is-size-5">{viewerPhotos.prev.name}</strong> <br>
|
||||
@@ -131,14 +126,14 @@
|
||||
</div>
|
||||
|
||||
<div class="level-right">
|
||||
<a href="{path + viewerPhotos.next.slug}" id="photo_next">
|
||||
<a href={path + viewerPhotos.next.slug} id="photo_next">
|
||||
<div class="media">
|
||||
<div class="media-content content has-text-right">
|
||||
<strong class="is-size-5">{viewerPhotos.next.name}</strong> <br>
|
||||
<span>{locationFull}</span>
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<img src="{getThumb(viewerPhotos.next, 'thumbnail')}" alt="{viewerPhotos.next.name}" width="200">
|
||||
<img src={getThumb(viewerPhotos.next, 'thumbnail')} alt={viewerPhotos.next.name} width="200">
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
Reference in New Issue
Block a user