portet blog

This commit is contained in:
cupcakearmy 2020-09-23 15:37:12 +02:00
parent b447b99159
commit 4df5603222
No known key found for this signature in database
GPG Key ID: D28129AE5654D9D9
17 changed files with 271 additions and 25 deletions

View File

@ -8,6 +8,7 @@
"dependencies": {
"axios": "^0.20.0",
"compression": "^1.7.1",
"dayjs": "^1.8.36",
"polka": "next",
"sirv": "^1.0.0"
},

View File

@ -0,0 +1,23 @@
<script>
export let src
export let alt
</script>
<style>
img {
width: calc(100% - 0.25em);
object-fit: cover;
object-position: center;
border: 0.125em solid var(--clr-primary);
transition: var(--animation);
transform: scale(1);
margin: 0;
}
img:hover {
transform: scale(1.1);
margin: 1em 0;
}
</style>
<img {src} {alt} />

View File

@ -5,7 +5,7 @@
{ name: 'About', href: '/about' },
{ name: 'Works', href: '/works' },
{ name: 'Projects', href: '/projects' },
{ name: 'Blog', href: 'https://blog.nicco.io' },
{ name: 'Blog', href: '/blog' },
{ name: 'Contact', href: '/contact' },
]

View File

@ -2,6 +2,7 @@
import SpacedLetters from './SpacedLetters.svelte'
export let title = ''
export let readable = false
</script>
<style>
@ -13,6 +14,6 @@
<div>
<h1>
<SpacedLetters letters={title} />
<SpacedLetters letters={title} {readable} />
</h1>
</div>

View File

@ -0,0 +1,31 @@
<script>
import dj from 'dayjs'
import { readingTimeInMinutes } from '../lib/readingTime'
export let post
export let full
function format(date) {
return dj(date).format('MMM D, YYYY')
}
$: created = format(post.date)
$: modified = format(post.modified)
</script>
<style>
.attributes {
display: flex;
justify-content: space-between;
font-weight: 400;
margin-top: -0.125em;
}
</style>
<div class="attributes">
<div>
{created}
{#if full && created !== modified}<br /> <small>Last update:{modified}</small>{/if}
</div>
<div>~ {readingTimeInMinutes(post.content)} min</div>
</div>

View File

@ -0,0 +1,46 @@
<script>
import ImageFrame from '../components/ImageFrame.svelte'
import PostAttributes from '../components/PostAttributes.svelte'
export let post
</script>
<style>
a {
display: block;
margin-bottom: 8em;
}
a > :global(img) {
height: 12em;
}
h2 {
margin-top: 0.25em;
position: relative;
top: 0;
transition: var(--animation);
background-color: #fff;
}
a:hover h2 {
top: -1em;
transform: scale(0.95);
}
a > :global(div) {
opacity: 1;
transition: var(--animation);
}
a:hover > :global(div) {
opacity: 0;
}
</style>
<a href={`blog/${post.slug}`}>
{#if post.featured}
<ImageFrame src={post.featured.sizes.medium_large} alt={post.featured.description} />
{/if}
<PostAttributes {post} />
<h2>
{@html post.title}
</h2>
</a>

View File

@ -2,16 +2,23 @@
import PageTitle from './PageTitle.svelte'
export let title = ''
export let expanded = true
export let readable = false
</script>
<style>
section {
max-width: 30em;
margin-bottom: 4em;
}
section.expanded {
margin-top: 5em;
}
</style>
<PageTitle {title} />
<PageTitle {title} {readable} />
<section>
<section class:expanded>
<slot />
</section>

View File

@ -1,6 +1,7 @@
<script>
export let letters = []
export let even = false
export let readable = false
</script>
<style>
@ -20,12 +21,15 @@
div.even {
font-size: 8vw;
}
div.readable {
letter-spacing: initial;
font-size: 4rem;
}
</style>
<div class:even>
<div class:even class:readable>
{#if even}
{#each letters as letter}
<span>{letter}</span>
{/each}
{#each letters as letter}<span>{letter}</span>{/each}
{:else}{letters}{/if}
</div>

View File

@ -0,0 +1,59 @@
<script>
export let content
</script>
<style>
div :global(.alignfull) {
width: calc(100vw - 6em);
margin-left: -2em;
}
div :global(.alignwide) {
width: calc(100% + 4em);
margin-left: -2em;
}
div :global(figure img) {
width: 100%;
height: 100%;
}
div :global(figure) {
margin: 0;
}
div :global(a) {
border-bottom: 0.125em solid var(--clr-primary);
}
div :global(pre) {
padding: 1em;
background: #0000000d;
overflow: auto;
}
div :global(code) {
background: #00000012;
padding: 0.25em;
}
div :global(pre code) {
background: initial;
padding: initial;
}
div :global(h1),
div :global(h2),
div :global(h3),
div :global(h4),
div :global(h5),
div :global(h6) {
margin: 0;
margin-top: 3em;
border-left: 0.2rem solid var(--clr-primary);
padding-left: 0.5rem;
margin-left: -0.7rem;
}
</style>
<div>
{@html content}
</div>

View File

@ -1,12 +1,10 @@
<script>
import ImageFrame from '../components/ImageFrame.svelte'
export let work
</script>
<style>
img {
width: 100%;
}
.title {
font-size: 2em;
line-height: 1;
@ -25,9 +23,13 @@
<div class="horizontal">
<div class="title regular">{work.title}</div>
<div><a href={work.link} target="_blank">{work.link.replace(/https?:\/\//, '')}</a></div>
<div>
<ion-icon name="link-outline" />
<a href={work.link} target="_blank">{work.link.replace(/https?:\/\//, '')}</a>
</div>
<img src={work.image.url} alt={work.image.description} />
</div>
<ImageFrame src={work.image.sizes.medium_large} alt={work.image.description} />
<div class="horizontal regular">
<div>{work.role}</div>
<div>{work.date}</div>

6
src/lib/readingTime.js Normal file
View File

@ -0,0 +1,6 @@
export function readingTimeInMinutes(text, options = {}) {
options = Object.assign({ wpm: 200 }, options)
const cleaned = text.replace(/(<.*?>)|(\\n)|(&#\d*?;)/g, '')
const words = cleaned.split(' ').length
return Math.round(words / options.wpm)
}

View File

@ -1,10 +1,11 @@
import axios from 'axios'
const isDev = process.env.NODE_ENV !== 'production'
const isDev = process.env.NODE_ENV !== 'production' && false
axios.defaults.baseURL = `${isDev ? 'http://localhost' : 'https://api.nicco.io'}/wp-json/wp/v2`
function normalize(post) {
return {
...post,
...post.acf,
id: post.id,
title: post.title.rendered,
@ -12,14 +13,29 @@ function normalize(post) {
}
}
function combineUrlAndParams(url, params) {
const p = new URLSearchParams({
per_page: 100,
...params,
}).toString()
return `${url}?${p}`
}
export async function getOne(url, params = {}) {
const p = new URLSearchParams(params).toString()
const { data } = await axios(`${url}?${p}`)
const { data } = await axios(combineUrlAndParams(url, params))
if (!data.length) return null
else return normalize(data[0])
}
export async function getAll(url, params = {}) {
const { data } = await axios(url)
return data.map(normalize)
const { data, headers } = await axios(combineUrlAndParams(url, params))
const totalPages = parseInt(headers['x-wp-totalpages'])
const results = [...data]
if (totalPages > 1) {
for (let page = 2; page <= totalPages; page++) {
const { data } = await axios(combineUrlAndParams(url, { ...params, page }))
results.push(...data)
}
}
return results.map(normalize)
}

View File

@ -41,7 +41,7 @@
<title>About</title>
</svelte:head>
<SimplePage title="About">
<SimplePage title="About" expanded={false}>
{@html data.content}
<img src="/images/about.jpg" alt="decoration" />
</SimplePage>

View File

@ -0,0 +1,21 @@
<script context="module">
import { getOne } from '../../lib/wp'
export async function preload({ params }) {
const { slug } = params
const post = await getOne('posts', { slug })
return { post }
}
</script>
<script>
import SimplePage from '../../components/SimplePage.svelte'
import WPAdapter from '../../components/WPAdapter.svelte'
import PostAttributes from '../../components/PostAttributes.svelte'
export let post
</script>
<SimplePage title={post.title} expanded={false} readable>
<PostAttributes {post} full />
<WPAdapter content={post.content} />
</SimplePage>

View File

@ -0,0 +1,25 @@
<script context="module">
import { getAll } from '../../lib/wp'
export async function preload() {
const data = await getAll('posts')
return { data }
}
</script>
<script>
import SimplePage from '../../components/SimplePage.svelte'
import PostPreview from '../../components/PostPreview.svelte'
export let data
</script>
<svelte:head>
<title>Blog</title>
</svelte:head>
<SimplePage title="Blog">
{#each data as post}
<PostPreview {post} />
{/each}
</SimplePage>

View File

@ -4,6 +4,9 @@
--ff: 'Jost', Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans,
Helvetica Neue, sans-serif;
--ff-alt: 'Playfair Display', serif;
--clr-primary: hsl(219, 90%, 80%);
--clr-secondary: hsl(64, 93%, 51%);
--animation: all 250ms ease;
}
body {
@ -32,6 +35,7 @@ h6 {
font-family: var(--ff-alt);
font-weight: normal;
margin: 1em 0 0.5em 0;
line-height: 1.2;
}
p {
@ -43,11 +47,6 @@ hr {
border: 0.1px solid var(--clr-primary);
}
:root {
--clr-primary: hsl(219, 90%, 80%);
--clr-secondary: hsl(64, 93%, 51%);
}
a {
color: inherit;
text-decoration: none;

View File

@ -225,6 +225,11 @@ cross-spawn@^6.0.5:
shebang-command "^1.2.0"
which "^1.2.9"
dayjs@^1.8.36:
version "1.8.36"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.36.tgz#be36e248467afabf8f5a86bae0de0cdceecced50"
integrity sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==
debug@2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"