mirror of
https://github.com/cupcakearmy/nicco.io.git
synced 2024-12-22 16:16:24 +00:00
portet blog
This commit is contained in:
parent
b447b99159
commit
4df5603222
@ -8,6 +8,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.20.0",
|
"axios": "^0.20.0",
|
||||||
"compression": "^1.7.1",
|
"compression": "^1.7.1",
|
||||||
|
"dayjs": "^1.8.36",
|
||||||
"polka": "next",
|
"polka": "next",
|
||||||
"sirv": "^1.0.0"
|
"sirv": "^1.0.0"
|
||||||
},
|
},
|
||||||
|
23
src/components/ImageFrame.svelte
Normal file
23
src/components/ImageFrame.svelte
Normal 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} />
|
@ -5,7 +5,7 @@
|
|||||||
{ name: 'About', href: '/about' },
|
{ name: 'About', href: '/about' },
|
||||||
{ name: 'Works', href: '/works' },
|
{ name: 'Works', href: '/works' },
|
||||||
{ name: 'Projects', href: '/projects' },
|
{ name: 'Projects', href: '/projects' },
|
||||||
{ name: 'Blog', href: 'https://blog.nicco.io' },
|
{ name: 'Blog', href: '/blog' },
|
||||||
{ name: 'Contact', href: '/contact' },
|
{ name: 'Contact', href: '/contact' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import SpacedLetters from './SpacedLetters.svelte'
|
import SpacedLetters from './SpacedLetters.svelte'
|
||||||
|
|
||||||
export let title = ''
|
export let title = ''
|
||||||
|
export let readable = false
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -13,6 +14,6 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h1>
|
<h1>
|
||||||
<SpacedLetters letters={title} />
|
<SpacedLetters letters={title} {readable} />
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
31
src/components/PostAttributes.svelte
Normal file
31
src/components/PostAttributes.svelte
Normal 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>
|
46
src/components/PostPreview.svelte
Normal file
46
src/components/PostPreview.svelte
Normal 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>
|
@ -2,16 +2,23 @@
|
|||||||
import PageTitle from './PageTitle.svelte'
|
import PageTitle from './PageTitle.svelte'
|
||||||
|
|
||||||
export let title = ''
|
export let title = ''
|
||||||
|
export let expanded = true
|
||||||
|
export let readable = false
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
section {
|
section {
|
||||||
max-width: 30em;
|
max-width: 30em;
|
||||||
|
margin-bottom: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.expanded {
|
||||||
|
margin-top: 5em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<PageTitle {title} />
|
<PageTitle {title} {readable} />
|
||||||
|
|
||||||
<section>
|
<section class:expanded>
|
||||||
<slot />
|
<slot />
|
||||||
</section>
|
</section>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
export let letters = []
|
export let letters = []
|
||||||
export let even = false
|
export let even = false
|
||||||
|
export let readable = false
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -20,12 +21,15 @@
|
|||||||
div.even {
|
div.even {
|
||||||
font-size: 8vw;
|
font-size: 8vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.readable {
|
||||||
|
letter-spacing: initial;
|
||||||
|
font-size: 4rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class:even>
|
<div class:even class:readable>
|
||||||
{#if even}
|
{#if even}
|
||||||
{#each letters as letter}
|
{#each letters as letter}<span>{letter}</span>{/each}
|
||||||
<span>{letter}</span>
|
|
||||||
{/each}
|
|
||||||
{:else}{letters}{/if}
|
{:else}{letters}{/if}
|
||||||
</div>
|
</div>
|
||||||
|
59
src/components/WPAdapter.svelte
Normal file
59
src/components/WPAdapter.svelte
Normal 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>
|
@ -1,12 +1,10 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import ImageFrame from '../components/ImageFrame.svelte'
|
||||||
|
|
||||||
export let work
|
export let work
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
img {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
@ -25,9 +23,13 @@
|
|||||||
|
|
||||||
<div class="horizontal">
|
<div class="horizontal">
|
||||||
<div class="title regular">{work.title}</div>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
<img src={work.image.url} alt={work.image.description} />
|
|
||||||
|
<ImageFrame src={work.image.sizes.medium_large} alt={work.image.description} />
|
||||||
<div class="horizontal regular">
|
<div class="horizontal regular">
|
||||||
<div>{work.role}</div>
|
<div>{work.role}</div>
|
||||||
<div>{work.date}</div>
|
<div>{work.date}</div>
|
||||||
|
6
src/lib/readingTime.js
Normal file
6
src/lib/readingTime.js
Normal 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)
|
||||||
|
}
|
@ -1,10 +1,11 @@
|
|||||||
import axios from 'axios'
|
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`
|
axios.defaults.baseURL = `${isDev ? 'http://localhost' : 'https://api.nicco.io'}/wp-json/wp/v2`
|
||||||
|
|
||||||
function normalize(post) {
|
function normalize(post) {
|
||||||
return {
|
return {
|
||||||
|
...post,
|
||||||
...post.acf,
|
...post.acf,
|
||||||
id: post.id,
|
id: post.id,
|
||||||
title: post.title.rendered,
|
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 = {}) {
|
export async function getOne(url, params = {}) {
|
||||||
const p = new URLSearchParams(params).toString()
|
const { data } = await axios(combineUrlAndParams(url, params))
|
||||||
const { data } = await axios(`${url}?${p}`)
|
|
||||||
if (!data.length) return null
|
if (!data.length) return null
|
||||||
else return normalize(data[0])
|
else return normalize(data[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAll(url, params = {}) {
|
export async function getAll(url, params = {}) {
|
||||||
const { data } = await axios(url)
|
const { data, headers } = await axios(combineUrlAndParams(url, params))
|
||||||
return data.map(normalize)
|
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)
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
<title>About</title>
|
<title>About</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<SimplePage title="About">
|
<SimplePage title="About" expanded={false}>
|
||||||
{@html data.content}
|
{@html data.content}
|
||||||
<img src="/images/about.jpg" alt="decoration" />
|
<img src="/images/about.jpg" alt="decoration" />
|
||||||
</SimplePage>
|
</SimplePage>
|
||||||
|
21
src/routes/blog/[slug].svelte
Normal file
21
src/routes/blog/[slug].svelte
Normal 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>
|
25
src/routes/blog/index.svelte
Normal file
25
src/routes/blog/index.svelte
Normal 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>
|
@ -4,6 +4,9 @@
|
|||||||
--ff: 'Jost', Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans,
|
--ff: 'Jost', Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans,
|
||||||
Helvetica Neue, sans-serif;
|
Helvetica Neue, sans-serif;
|
||||||
--ff-alt: 'Playfair Display', serif;
|
--ff-alt: 'Playfair Display', serif;
|
||||||
|
--clr-primary: hsl(219, 90%, 80%);
|
||||||
|
--clr-secondary: hsl(64, 93%, 51%);
|
||||||
|
--animation: all 250ms ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@ -32,6 +35,7 @@ h6 {
|
|||||||
font-family: var(--ff-alt);
|
font-family: var(--ff-alt);
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
margin: 1em 0 0.5em 0;
|
margin: 1em 0 0.5em 0;
|
||||||
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
@ -43,11 +47,6 @@ hr {
|
|||||||
border: 0.1px solid var(--clr-primary);
|
border: 0.1px solid var(--clr-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
|
||||||
--clr-primary: hsl(219, 90%, 80%);
|
|
||||||
--clr-secondary: hsl(64, 93%, 51%);
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
@ -225,6 +225,11 @@ cross-spawn@^6.0.5:
|
|||||||
shebang-command "^1.2.0"
|
shebang-command "^1.2.0"
|
||||||
which "^1.2.9"
|
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:
|
debug@2.6.9:
|
||||||
version "2.6.9"
|
version "2.6.9"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||||
|
Loading…
Reference in New Issue
Block a user