First commit
Explore Svelte and Sapper
This commit is contained in:
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
.DS_Store
|
||||||
|
/node_modules/
|
||||||
|
/src/node_modules/@sapper/
|
||||||
|
yarn-error.log
|
||||||
|
/cypress/screenshots/
|
||||||
|
/__sapper__/
|
||||||
35
package.json
Normal file
35
package.json
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "housesof",
|
||||||
|
"description": "Houses Of website",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "sapper dev",
|
||||||
|
"build": "sapper build --legacy",
|
||||||
|
"export": "sapper export --legacy",
|
||||||
|
"start": "node __sapper__/build"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"bulma": "^0.8.0",
|
||||||
|
"compression": "^1.7.4",
|
||||||
|
"dayjs": "^1.8.18",
|
||||||
|
"polka": "^1.0.0-next.9",
|
||||||
|
"sirv": "^0.4.2",
|
||||||
|
"slug": "^1.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.7.7",
|
||||||
|
"@babel/plugin-syntax-dynamic-import": "^7.7.4",
|
||||||
|
"@babel/plugin-transform-runtime": "^7.7.6",
|
||||||
|
"@babel/preset-env": "^7.7.7",
|
||||||
|
"@babel/runtime": "^7.7.7",
|
||||||
|
"@rollup/plugin-node-resolve": "^6.0.0",
|
||||||
|
"@rollup/plugin-replace": "^2.3.0",
|
||||||
|
"rollup": "^1.27.14",
|
||||||
|
"rollup-plugin-babel": "^4.3.3",
|
||||||
|
"rollup-plugin-commonjs": "^10.1.0",
|
||||||
|
"rollup-plugin-svelte": "^5.1.1",
|
||||||
|
"rollup-plugin-terser": "^5.1.3",
|
||||||
|
"sapper": "^0.27.9",
|
||||||
|
"svelte": "^3.16.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
1568
pnpm-lock.yaml
generated
Normal file
1568
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
102
rollup.config.js
Normal file
102
rollup.config.js
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import resolve from '@rollup/plugin-node-resolve'
|
||||||
|
import replace from '@rollup/plugin-replace'
|
||||||
|
import commonjs from 'rollup-plugin-commonjs'
|
||||||
|
import svelte from 'rollup-plugin-svelte'
|
||||||
|
import babel from 'rollup-plugin-babel'
|
||||||
|
import { terser } from 'rollup-plugin-terser'
|
||||||
|
import config from 'sapper/config/rollup.js'
|
||||||
|
import pkg from './package.json'
|
||||||
|
|
||||||
|
const mode = process.env.NODE_ENV
|
||||||
|
const dev = mode === 'development'
|
||||||
|
const legacy = !!process.env.SAPPER_LEGACY_BUILD
|
||||||
|
|
||||||
|
const onwarn = (warning, onwarn) => (warning.code === 'CIRCULAR_DEPENDENCY' && /[/\\]@sapper[/\\]/.test(warning.message)) || onwarn(warning)
|
||||||
|
const dedupe = importee => importee === 'svelte' || importee.startsWith('svelte/')
|
||||||
|
|
||||||
|
export default {
|
||||||
|
client: {
|
||||||
|
input: config.client.input(),
|
||||||
|
output: config.client.output(),
|
||||||
|
plugins: [
|
||||||
|
replace({
|
||||||
|
'process.browser': true,
|
||||||
|
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||||
|
}),
|
||||||
|
svelte({
|
||||||
|
dev,
|
||||||
|
hydratable: true,
|
||||||
|
emitCss: true
|
||||||
|
}),
|
||||||
|
resolve({
|
||||||
|
browser: true,
|
||||||
|
dedupe
|
||||||
|
}),
|
||||||
|
commonjs(),
|
||||||
|
|
||||||
|
legacy && babel({
|
||||||
|
extensions: ['.js', '.mjs', '.html', '.svelte'],
|
||||||
|
runtimeHelpers: true,
|
||||||
|
exclude: ['node_modules/@babel/**'],
|
||||||
|
presets: [
|
||||||
|
['@babel/preset-env', {
|
||||||
|
targets: '> 0.25%, not dead'
|
||||||
|
}]
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
'@babel/plugin-syntax-dynamic-import',
|
||||||
|
['@babel/plugin-transform-runtime', {
|
||||||
|
useESModules: true
|
||||||
|
}]
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
|
||||||
|
!dev && terser({
|
||||||
|
module: true
|
||||||
|
})
|
||||||
|
],
|
||||||
|
|
||||||
|
onwarn,
|
||||||
|
},
|
||||||
|
|
||||||
|
server: {
|
||||||
|
input: config.server.input(),
|
||||||
|
output: config.server.output(),
|
||||||
|
plugins: [
|
||||||
|
replace({
|
||||||
|
'process.browser': false,
|
||||||
|
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||||
|
}),
|
||||||
|
svelte({
|
||||||
|
generate: 'ssr',
|
||||||
|
dev
|
||||||
|
}),
|
||||||
|
resolve({
|
||||||
|
browser: true,
|
||||||
|
dedupe
|
||||||
|
}),
|
||||||
|
commonjs()
|
||||||
|
],
|
||||||
|
external: Object.keys(pkg.dependencies).concat(
|
||||||
|
require('module').builtinModules || Object.keys(process.binding('natives'))
|
||||||
|
),
|
||||||
|
|
||||||
|
onwarn,
|
||||||
|
},
|
||||||
|
|
||||||
|
serviceworker: {
|
||||||
|
input: config.serviceworker.input(),
|
||||||
|
output: config.serviceworker.output(),
|
||||||
|
plugins: [
|
||||||
|
resolve(),
|
||||||
|
replace({
|
||||||
|
'process.browser': true,
|
||||||
|
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||||
|
}),
|
||||||
|
commonjs(),
|
||||||
|
!dev && terser()
|
||||||
|
],
|
||||||
|
|
||||||
|
onwarn,
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/client.js
Normal file
5
src/client.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import * as sapper from '@sapper/app'
|
||||||
|
|
||||||
|
sapper.start({
|
||||||
|
target: document.getElementById('site')
|
||||||
|
})
|
||||||
14
src/components/Nav.svelte
Normal file
14
src/components/Nav.svelte
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<script>
|
||||||
|
export let segment;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
<li><a class:selected='{segment === undefined}' href='.'>home</a></li>
|
||||||
|
<li><a class:selected='{segment === "about"}' href='about'>about</a></li>
|
||||||
|
|
||||||
|
<!-- for the blog link, we're using rel=prefetch so that Sapper prefetches
|
||||||
|
the blog data when we hover over the link or tap it on a touchscreen -->
|
||||||
|
<li><a rel=prefetch class:selected='{segment === "blog"}' href='blog'>blog</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
36
src/components/Photo.svelte
Normal file
36
src/components/Photo.svelte
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<script>
|
||||||
|
import { slide } from 'svelte/transition'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import advancedFormat from 'dayjs/plugin/advancedFormat'
|
||||||
|
import * as fn from '../functions'
|
||||||
|
|
||||||
|
export let photo
|
||||||
|
export let index
|
||||||
|
export let location
|
||||||
|
|
||||||
|
// Manipulate data
|
||||||
|
const thumbnail = photo.image.data.thumbnails.find(t => t.url.includes('key=large'))
|
||||||
|
index = (index < 10 ? '0' : null) + index
|
||||||
|
|
||||||
|
// Format the date
|
||||||
|
dayjs.extend(advancedFormat)
|
||||||
|
const date = dayjs(photo.created_on).format('MMM Do, YYYY')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="card" in:slide out:slide>
|
||||||
|
<div class="card-image">
|
||||||
|
<figure class="image is-4by3">
|
||||||
|
<img src="{thumbnail.url}" alt="{photo.name}, {location.name}, {location.country.name}" width="{thumbnail.width}" height="{thumbnail.height}">
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-content">
|
||||||
|
<h4 class="title is-4">{photo.name}</h4>
|
||||||
|
<p>{location.name}, {location.country.name}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="card-footer">
|
||||||
|
<span class="card-footer-item">{date}</span>
|
||||||
|
<span class="card-footer-item">#{index}</span>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
38
src/functions.js
Normal file
38
src/functions.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
** Get API function
|
||||||
|
*/
|
||||||
|
export const api = async (query) => {
|
||||||
|
const res = await fetch('http://api.housesof.localhost/how/gql?access_token=NJk0urljsdSvApUDzWxGgoO6', {
|
||||||
|
method: 'post',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ query: `{${query}}` })
|
||||||
|
})
|
||||||
|
const data = await res.json()
|
||||||
|
return data.data
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Load API function
|
||||||
|
*/
|
||||||
|
export const loadAPI = async (requests = []) => {
|
||||||
|
// Fetch all requests
|
||||||
|
return await Promise.all(requests.map(req => api(req)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => data.data)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Slufigy a string
|
||||||
|
*/
|
||||||
|
export const slug = string => {
|
||||||
|
return string.toString().toLowerCase().trim()
|
||||||
|
.normalize('NFD')
|
||||||
|
.replace(/[\u0300-\u036f]/g, '')
|
||||||
|
.replace(/\s+/g, '-')
|
||||||
|
.replace(/&/g, '-and-')
|
||||||
|
.replace(/[^\w\-]+/g, '')
|
||||||
|
.replace(/\-\-+/g, '-')
|
||||||
|
}
|
||||||
21
src/parts/Footer.svelte
Normal file
21
src/parts/Footer.svelte
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<script>
|
||||||
|
import { site } from '../store'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- <pre>{JSON.stringify($site, '', 2)}</pre> -->
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="left">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="right">
|
||||||
|
<div class="instagram">
|
||||||
|
<a href="https://instagram.com/cetrucflotte" target="_blank">Instagram</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ctf">
|
||||||
|
<a href="https://cetrucflotte.com" target="_blank">A project by <img src="/assets/img/logo-cetrucflotte.png" alt="Cetrucflotte" width="118" height="22"></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
40
src/routes/_error.svelte
Normal file
40
src/routes/_error.svelte
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<script>
|
||||||
|
export let status;
|
||||||
|
export let error;
|
||||||
|
|
||||||
|
const dev = process.env.NODE_ENV === 'development';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h1, p {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2.8em;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 0 0 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 1em auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 480px) {
|
||||||
|
h1 {
|
||||||
|
font-size: 4em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>{status}</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<h1>{status}</h1>
|
||||||
|
|
||||||
|
<p>{error.message}</p>
|
||||||
|
|
||||||
|
{#if dev && error.stack}
|
||||||
|
<pre>{error.stack}</pre>
|
||||||
|
{/if}
|
||||||
86
src/routes/_layout.svelte
Normal file
86
src/routes/_layout.svelte
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<script context="module">
|
||||||
|
import { locations, countries, site } from '../store'
|
||||||
|
|
||||||
|
export async function preload (page, segment) {
|
||||||
|
const res = await this.fetch('http://api.housesof.localhost/how/gql?access_token=NJk0urljsdSvApUDzWxGgoO6', {
|
||||||
|
method: 'post',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ query: `{
|
||||||
|
site {
|
||||||
|
data {
|
||||||
|
description
|
||||||
|
explore_globe
|
||||||
|
explore_list
|
||||||
|
instagram
|
||||||
|
}
|
||||||
|
}
|
||||||
|
countries {
|
||||||
|
data {
|
||||||
|
name
|
||||||
|
flag { metadata }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
locations (filter: { status_eq: "published" }) {
|
||||||
|
data {
|
||||||
|
name
|
||||||
|
region
|
||||||
|
country { name }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`})
|
||||||
|
})
|
||||||
|
const data = await res.json()
|
||||||
|
countries.set(data.data.countries.data)
|
||||||
|
locations.set(data.data.locations.data)
|
||||||
|
site.set(data.data.site.data[0])
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import '../../node_modules/bulma/css/bulma.min.css'
|
||||||
|
import * as fn from '../functions'
|
||||||
|
|
||||||
|
// import SwitcherLarge from '../components/Photos.svelte'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav class="navbar is-danger" role="navigation" aria-label="main navigation">
|
||||||
|
<div class="container">
|
||||||
|
<div class="navbar-start">
|
||||||
|
<div class="navbar-brand">
|
||||||
|
<a class="navbar-item" href="/">
|
||||||
|
<strong>Houses Of</strong>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
|
<a class="navbar-link" href="/">Locations</a>
|
||||||
|
<div class="navbar-dropdown">
|
||||||
|
{#each $locations as location}
|
||||||
|
<a class="navbar-item" href="/location/{fn.slug(location.name)}">{location.name}</a>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<slot></slot>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="content columns">
|
||||||
|
<div class="column is-7">
|
||||||
|
<p><strong>Houses Of</strong></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="column columns">
|
||||||
|
<p class="column">
|
||||||
|
<a href="https://instagram.com/{$site.instagram}" target="_blank">Instagram</a>
|
||||||
|
</p>
|
||||||
|
<p class="column">
|
||||||
|
<a href="https://cetrucflotte.com" target="_blank">A project by Cetrucflotte</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
7
src/routes/about.svelte
Normal file
7
src/routes/about.svelte
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<svelte:head>
|
||||||
|
<title>About</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<h1>About this site</h1>
|
||||||
|
|
||||||
|
<p>This is the 'about' page. There's not much here.</p>
|
||||||
29
src/routes/index.svelte
Normal file
29
src/routes/index.svelte
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<script>
|
||||||
|
import { slide } from 'svelte/transition'
|
||||||
|
import { locations, countries, site } from '../store'
|
||||||
|
import * as fn from '../functions'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>Houses Of - Beautiful houses of planet Earth</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<div class="container" in:slide out:slide>
|
||||||
|
<section class="section">
|
||||||
|
<h1 class="title is-2">Houses Of</h1>
|
||||||
|
<article class="message is-dark">
|
||||||
|
<div class="message-body">{$site.description}</div>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section">
|
||||||
|
<h3 class="title is-3">Locations</h3>
|
||||||
|
<ul>
|
||||||
|
{#each $locations as location}
|
||||||
|
<li>
|
||||||
|
<a href="/location/{fn.slug(location.name)}">{location.name}</a>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
54
src/routes/location/[location].svelte
Normal file
54
src/routes/location/[location].svelte
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<script context="module">
|
||||||
|
export async function preload (page, session) {
|
||||||
|
const location = await this.fetch('//api.housesof.localhost/how/gql?access_token=NJk0urljsdSvApUDzWxGgoO6', {
|
||||||
|
method: 'post',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ query: `{
|
||||||
|
locations (filter: { name_eq: "${page.params.location}" }) {
|
||||||
|
data {
|
||||||
|
name
|
||||||
|
region
|
||||||
|
country { name }
|
||||||
|
description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`})
|
||||||
|
})
|
||||||
|
const photos = await this.fetch(`http://api.housesof.localhost/how/items/photos?fields=id,name,image.data,created_on&filter[location.name][rlike]=%${page.params.location}%`)
|
||||||
|
const locationData = await location.json()
|
||||||
|
const photosData = await photos.json()
|
||||||
|
return {
|
||||||
|
location: locationData.data.locations.data[0],
|
||||||
|
photos: photosData.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { slide } from 'svelte/transition'
|
||||||
|
import Photo from '../../components/Photo.svelte'
|
||||||
|
|
||||||
|
export let location
|
||||||
|
export let photos
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>Houses Of - Beautiful houses of {location.name}, {location.country.name}</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<div class="section container" in:slide out:slide>
|
||||||
|
<div class="content">
|
||||||
|
<h1 class="title is-2">{location.name}, {location.country.name}</h1>
|
||||||
|
{#if location.description}
|
||||||
|
<p>Houses Of {location.name} {location.description}</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="columns">
|
||||||
|
{#each photos as photo, index (photo.id)}
|
||||||
|
<div class="column">
|
||||||
|
<Photo {photo} {location} index={index + 1} />
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
17
src/server.js
Normal file
17
src/server.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import sirv from 'sirv'
|
||||||
|
import polka from 'polka'
|
||||||
|
import compression from 'compression'
|
||||||
|
import * as sapper from '@sapper/server'
|
||||||
|
|
||||||
|
const { PORT, NODE_ENV } = process.env
|
||||||
|
const dev = NODE_ENV === 'development'
|
||||||
|
|
||||||
|
polka() // You can also use Express
|
||||||
|
.use(
|
||||||
|
compression({ threshold: 0 }),
|
||||||
|
sirv('static', { dev }),
|
||||||
|
sapper.middleware()
|
||||||
|
)
|
||||||
|
.listen(PORT, err => {
|
||||||
|
if (err) console.log('error', err)
|
||||||
|
})
|
||||||
82
src/service-worker.js
Normal file
82
src/service-worker.js
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { timestamp, files, shell, routes } from '@sapper/service-worker'
|
||||||
|
|
||||||
|
const ASSETS = `cache${timestamp}`
|
||||||
|
|
||||||
|
// `shell` is an array of all the files generated by the bundler,
|
||||||
|
// `files` is an array of everything in the `static` directory
|
||||||
|
const to_cache = shell.concat(files)
|
||||||
|
const cached = new Set(to_cache)
|
||||||
|
|
||||||
|
self.addEventListener('install', event => {
|
||||||
|
event.waitUntil(
|
||||||
|
caches
|
||||||
|
.open(ASSETS)
|
||||||
|
.then(cache => cache.addAll(to_cache))
|
||||||
|
.then(() => {
|
||||||
|
self.skipWaiting()
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
self.addEventListener('activate', event => {
|
||||||
|
event.waitUntil(
|
||||||
|
caches.keys().then(async keys => {
|
||||||
|
// delete old caches
|
||||||
|
for (const key of keys) {
|
||||||
|
if (key !== ASSETS) await caches.delete(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.clients.claim()
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
self.addEventListener('fetch', event => {
|
||||||
|
if (event.request.method !== 'GET' || event.request.headers.has('range')) return
|
||||||
|
|
||||||
|
const url = new URL(event.request.url)
|
||||||
|
|
||||||
|
// don't try to handle e.g. data: URIs
|
||||||
|
if (!url.protocol.startsWith('http')) return
|
||||||
|
|
||||||
|
// ignore dev server requests
|
||||||
|
if (url.hostname === self.location.hostname && url.port !== self.location.port) return
|
||||||
|
|
||||||
|
// always serve static files and bundler-generated assets from cache
|
||||||
|
if (url.host === self.location.host && cached.has(url.pathname)) {
|
||||||
|
event.respondWith(caches.match(event.request))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// for pages, you might want to serve a shell `service-worker-index.html` file,
|
||||||
|
// which Sapper has generated for you. It's not right for every
|
||||||
|
// app, but if it's right for yours then uncomment this section
|
||||||
|
/*
|
||||||
|
if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) {
|
||||||
|
event.respondWith(caches.match('/service-worker-index.html'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (event.request.cache === 'only-if-cached') return
|
||||||
|
|
||||||
|
// for everything else, try the network first, falling back to
|
||||||
|
// cache if the user is offline. (If the pages never change, you
|
||||||
|
// might prefer a cache-first approach to a network-first one.)
|
||||||
|
event.respondWith(
|
||||||
|
caches
|
||||||
|
.open(`offline${timestamp}`)
|
||||||
|
.then(async cache => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(event.request)
|
||||||
|
cache.put(event.request, response.clone())
|
||||||
|
return response
|
||||||
|
} catch(err) {
|
||||||
|
const response = await cache.match(event.request)
|
||||||
|
if (response) return response
|
||||||
|
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
15
src/store.js
Normal file
15
src/store.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import * as fn from './functions'
|
||||||
|
import { writable } from 'svelte/store'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
Site related
|
||||||
|
========================================================================== */
|
||||||
|
export let currentLocation = {}
|
||||||
|
export let loaded = writable(false)
|
||||||
|
|
||||||
|
// Data
|
||||||
|
export let locations = writable()
|
||||||
|
export let countries = writable()
|
||||||
|
export let site = writable()
|
||||||
17
src/template.html
Normal file
17
src/template.html
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
|
||||||
|
%sapper.base%
|
||||||
|
%sapper.styles%
|
||||||
|
%sapper.head%
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="site">%sapper.html%</div>
|
||||||
|
|
||||||
|
%sapper.scripts%
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user