Use a component for the pagination

Make the component and the page communicate with events to add more photos
This commit is contained in:
2020-03-02 22:27:39 +01:00
parent 6a58938e71
commit 1db9217cd0
2 changed files with 224 additions and 175 deletions

View File

@@ -0,0 +1,67 @@
<script>
import { onMount, createEventDispatcher } from 'svelte'
import { currentLocation } from '../store'
const dispatch = createEventDispatcher()
// Props
export let photos
export let paginatedPhotos
export let photosPerPage
// Variables
let currentIndex = photosPerPage
const pagesTotal = Math.ceil(photos.length / photosPerPage)
const pagesArray = Array.from({ length: pagesTotal }, (v, k) => k + 1).reverse()
let pageTranslate = 100 - (100 / pagesTotal)
// Add more photos to the loop
const displayMorePhotos = () => {
if (currentIndex < photos.length) {
// Display the X next hidden photos
const photosToAppend = photos.filter(photo => photo.hidden === true).splice(0, photosPerPage)
photosToAppend.forEach(photo => photo.hidden = false)
// Merge new photos to show to the existing ones
dispatch('updatePagination', {
paginatedPhotos: [...paginatedPhotos, ...photosToAppend]
})
// Increment current index
currentIndex = currentIndex + photosPerPage
// Animate the pagination
pageTranslate = pageTranslate - (100 / pagesTotal)
} else {
currentIndex = photos.length
}
}
</script>
<section class="pagination">
{#if photos.length && currentIndex <= photos.length}
<div class="pagination__page" class:disabled={currentIndex === photos.length}
on:click={displayMorePhotos}
on:mouseenter={() => pageTranslate = pageTranslate - (100 / pagesTotal) * 0.666}
on:mouseleave={() => pageTranslate = pageTranslate + (100 / pagesTotal) * 0.666}
>
<div class="pagination__info">page</div>
<div class="pagination__numbers">
<div class="scroll" style="transform: translateY(-{pageTranslate}%);">
{#each pagesArray as page}
<span>{page}</span>
{/each}
</div>
</div>
/{pagesTotal}
</div>
<p class="pagination__caption style-caps">See more photos</p>
{:else}
{#if $currentLocation}
<div class="pagination__message">
<h3>That's all folks!</h3>
<p class="pagination__caption style-caps">Come back later to check out <br>new photos of {$currentLocation.name}</p>
</div>
{/if}
{/if}
</section>

View File

@@ -1,212 +1,194 @@
<script context="module"> <script context="module">
import { import {
apiEndpoints, apiEndpoints,
site, site,
locations, locations,
currentLocation, currentLocation,
currentPhotos currentPhotos
} from '../../../store' } from '../../../store'
import { stores } from '@sapper/app' import { stores } from '@sapper/app'
// Preload data // Preload data
export async function preload (page, session) { export async function preload (page, session) {
// Load photos // Load photos
const req = await this.fetch(`${apiEndpoints.rest}/items/photos?fields=id,name,date,slug,image.*,location.*,location.country.*,created_on,modified_on&filter[location.slug][rlike]=%${page.params.location}%&limit=-1&sort=-created_on,name`) const req = await this.fetch(`${apiEndpoints.rest}/items/photos?fields=id,name,slug,image.*,location.*,location.country.*,created_on,modified_on&filter[location.slug][rlike]=%${page.params.location}%&limit=-1&sort=-created_on,name`)
const photos = await req.json() console.log(req.headers.host)
if (req.ok) { const photos = await req.json()
return { photos: photos.data } if (req.ok) {
} return { photos: photos.data }
this.error(404, 'Not found') }
} this.error(404, 'Not found')
}
</script> </script>
<script> <script>
import { onMount } from 'svelte' import { onMount } from 'svelte'
const { page } = stores() import * as fn from '../../../functions'
const { page } = stores()
// Dependencies // Dependencies
import AOS from 'aos' import AOS from 'aos'
import 'lazysizes' import 'lazysizes'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import advancedFormat from 'dayjs/plugin/advancedFormat' import advancedFormat from 'dayjs/plugin/advancedFormat'
import relativeTime from 'dayjs/plugin/relativeTime' import relativeTime from 'dayjs/plugin/relativeTime'
dayjs.extend(advancedFormat) dayjs.extend(advancedFormat)
dayjs.extend(relativeTime) dayjs.extend(relativeTime)
// Components // Components
import IconGlobe from '../../../atoms/IconGlobe' import IconGlobe from '../../../atoms/IconGlobe'
import IconGlobeSmall from '../../../atoms/IconGlobeSmall' import IconGlobeSmall from '../../../atoms/IconGlobeSmall'
import LinkChange from '../../../atoms/LinkChange' import LinkChange from '../../../atoms/LinkChange'
import ToggleLayout from '../../../atoms/ToggleLayout' import ToggleLayout from '../../../atoms/ToggleLayout'
import Photo from '../../../molecules/Photo' import Photo from '../../../molecules/Photo'
import Switcher from '../../../molecules/Switcher' import Switcher from '../../../molecules/Switcher'
import Footer from '../../../organisms/Footer' import Pagination from '../../../organisms/Pagination'
import Footer from '../../../organisms/Footer'
import SocialMetas from '../../../utils/SocialMetas'
// Props and variables // Props and variables
export let photos export let photos
let layoutSetting let layoutSetting
// Update current location // Update current location
const location = $locations.find(loc => loc.slug === $page.params.location) const location = $locations.find(loc => loc.slug === $page.params.location)
currentLocation.set(location) currentLocation.set(location)
currentPhotos.set(photos) currentPhotos.set(photos)
// Define dates // Define dates
$: latestPhoto = photos[0] $: latestPhoto = photos[0]
$: dateUpdatedFull = latestPhoto ? dayjs(latestPhoto.modified_on).format('MMM Do, YYYY') : '' $: dateUpdatedFull = latestPhoto ? dayjs(latestPhoto.modified_on).format('MMM Do, YYYY') : ''
$: dateUpdatedDatetime = latestPhoto ?dayjs(latestPhoto.modified_on).format('YYYY-MM-DDThh:mm:ss') : '' $: dateUpdatedDatetime = latestPhoto ?dayjs(latestPhoto.modified_on).format('YYYY-MM-DDThh:mm:ss') : ''
$: dateUpdatedRelative = latestPhoto ?dayjs().to(dayjs(latestPhoto.modified_on)) : '' $: dateUpdatedRelative = latestPhoto ?dayjs().to(dayjs(latestPhoto.modified_on)) : ''
$: lastUpdated = latestPhoto ? (dayjs(latestPhoto.modified_on).isBefore(dayjs().subtract(1, 'M'))) ? dateUpdatedFull : dateUpdatedRelatives : '' $: lastUpdated = latestPhoto ? (dayjs(latestPhoto.modified_on).isBefore(dayjs().subtract(1, 'M'))) ? dateUpdatedFull : dateUpdatedRelatives : ''
/* /*
** Pagination ** Pagination
*/ */
let photosPerPage = 2 // 12 let photosPerPage = 2 // 12
let currentIndex = photosPerPage let currentIndex = photosPerPage
const pagesTotal = Math.ceil(photos.length / photosPerPage)
const pages = Array.from({ length: pagesTotal }, (v, k) => k + 1).reverse()
let pageTranslate = 100 - (100 / pagesTotal)
// Hide photos by default // Hide photos by default
photos.forEach((photo, index) => photo.hidden = (index + 1 > photosPerPage) ? true : false) photos.forEach((photo, index) => photo.hidden = (index + 1 > photosPerPage) ? true : false)
let paginatedPhotos = photos.filter(photo => photo.hidden === false) let paginatedPhotos = photos.filter(photo => photo.hidden === false)
// Add more photos to the loop // Update pagination event from Pagination component
const displayMorePhotos = () => { const updatePagination = event => paginatedPhotos = event.detail.paginatedPhotos
if (currentIndex < photos.length) {
// Display the X next hidden photos
const photosToAppend = photos.filter(photo => photo.hidden === true).splice(0, photosPerPage)
photosToAppend.forEach(photo => photo.hidden = false)
// Merge new photos to show to the existing ones
paginatedPhotos = [...paginatedPhotos, ...photosToAppend]
// Increment current index
currentIndex = currentIndex + photosPerPage
// Animate the pagination
pageTranslate = pageTranslate - (100 / pagesTotal)
} else {
currentIndex = photos.length
}
}
/* /*
** Run code on browser only ** Run code on browser only
*/ */
onMount(() => { onMount(() => {
// Get layout setting from storage // Get layout setting from storage
layoutSetting = localStorage.getItem('photosLayout') layoutSetting = localStorage.getItem('photosLayout')
if (process.browser) {
// Scroll apparitions
AOS.init()
}
})
if (process.browser) {
// Scroll apparitions
AOS.init()
}
})
</script> </script>
<svelte:head> <svelte:head>
<title>Houses Of - Beautiful houses of {location.name}, {location.country.name}</title> <title>Houses Of Beautiful houses of {location.name}, {location.country.name}</title>
<meta name="description" content="Houses Of {location.name} {location.description}">
<SocialMetas
url="https://housesof.world/location/{location.country.slug}/{location.slug}"
title="Houses Of Beautiful houses of {location.name}, {location.country.name}"
description="Houses Of {location.name} {location.description}"
image={latestPhoto ? fn.getThumbnail(latestPhoto.image.private_hash, 1200, 630) : null}
/>
</svelte:head> </svelte:head>
<section class="place"> <section class="place">
<div class="place__title"> <div class="place__title">
<h1 class="title-location title-location--big"> <h1 class="title-location title-location--big">
<span class="top">Houses <em>of</em></span> <span class="top">Houses <em>of</em></span>
<span class="bottom">{location.name}</span> <span class="bottom">{location.name}</span>
</h1> </h1>
<a href="/choose" class="button-control button-control--big button-control--dashed"> <a href="/choose" class="button-control button-control--big button-control--dashed">
<span class="center"> <span class="center">
<IconGlobe width="44" color="#fff" /> <IconGlobe width="44" color="#fff" />
<span>Change</span> <span>Change</span>
</span> </span>
<svg> <svg>
<circle cx="50%" cy="50%" r="43%" /> <circle cx="50%" cy="50%" r="43%" />
</svg> </svg>
</a> </a>
</div> </div>
<div class="place__wrap wrap"> <div class="place__wrap wrap">
<div class="place__description"> <div class="place__description">
<div class="wrapper"> <div class="wrapper">
<p>{$site.description}</p> <p>{$site.description}</p>
<p> {#if location.description}
Houses Of <p>
<LinkChange href="/choose" text={location.name}> Houses Of
<IconGlobeSmall width="14" color="#999" /> <LinkChange href="/choose" text={location.name}>
</LinkChange> <IconGlobeSmall width="14" color="#999" />
{location.description} </LinkChange>
</p> {location.description}
<p class="updated style-caps"> </p>
<strong>Updated</strong> {/if}
<time datetime={dateUpdatedDatetime} title={dateUpdatedFull}>{lastUpdated}</time>
</p>
<ToggleLayout /> {#if photos.length}
</div> <p class="updated style-caps">
</div> <strong>Updated</strong>
</div> <time datetime={dateUpdatedDatetime} title={dateUpdatedFull}>{lastUpdated}</time>
</p>
<div class="place__illustration"> <ToggleLayout />
<div class="place__illustration--left side"></div> {/if}
<div class="place__illustration--center"></div> </div>
<div class="place__illustration--right side"></div> </div>
</div> </div>
<div class="place__illustration">
<div class="place__illustration--left side"></div>
<div class="place__illustration--center"></div>
<div class="place__illustration--right side"></div>
</div>
</section> </section>
<section class="photos photos--{layoutSetting || 'list'}"> <section class="photos photos--{layoutSetting || 'list'}">
<div class="photos__sidewrap wrap"> <div class="photos__sidewrap wrap">
<aside class="photos__side"> <aside class="photos__side">
<Switcher type="switcher--side" /> <Switcher type="switcher--side" />
<p class="updated style-caps"> {#if photos.length}
<strong>Updated</strong> <p class="updated style-caps">
<time datetime={dateUpdatedDatetime} title={dateUpdatedFull}>{lastUpdated}</time> <strong>Updated</strong>
</p> <time datetime={dateUpdatedDatetime} title={dateUpdatedFull}>{lastUpdated}</time>
</aside> </p>
</div> {/if}
</aside>
</div>
{#if photos.length} {#if photos.length}
<div class="photos__view wrap"> <div class="photos__view wrap">
{#each paginatedPhotos as photo, index} {#each paginatedPhotos as photo, index}
<Photo <Photo
photo={photo} photo={photo}
layout={layoutSetting} index={photos.length - photos.indexOf(photo)}
index={photos.length - (photos.indexOf(photo))} layout={layoutSetting}
/> />
{/each} {/each}
</div> </div>
<section class="pagination"> <Pagination
{#if photos.length && currentIndex <= photos.length} {photos} {paginatedPhotos} {photosPerPage}
<div class="pagination__page" class:disabled={currentIndex === photos.length} on:updatePagination={updatePagination}
on:click={displayMorePhotos} />
on:mouseenter={() => pageTranslate = pageTranslate - ((100 / pagesTotal) * 0.666)}
on:mouseleave={() => pageTranslate = pageTranslate + ((100 / pagesTotal) * 0.666)}
>
<div class="pagination__info">page</div>
<div class="pagination__numbers">
<div class="scroll" style="transform: translateY(-{pageTranslate}%);">
{#each pages as page}
<span>{page}</span>
{/each}
</div>
</div>
/{pagesTotal}
</div>
<p class="pagination__caption style-caps">See more photos</p>
{:else} {:else}
<div class="pagination__message"> <div class="wrap" style="padding-top: 20vw; padding-bottom: 20vw;">
<h3>That's all folks!</h3> <p style="text-align: center; color: #333;">No photo for {location.name}</p>
<p class="pagination__caption style-caps">Come back later to check out <br>new photos of {location.name}</p> </div>
</div> {/if}
{/if}
</section>
{/if}
</section> </section>
<Footer /> <Footer />