mirror of
https://github.com/cupcakearmy/nicco.io.git
synced 2024-12-22 08:06:29 +00:00
portet blog
This commit is contained in:
parent
b447b99159
commit
4df5603222
@ -8,6 +8,7 @@
|
||||
"dependencies": {
|
||||
"axios": "^0.20.0",
|
||||
"compression": "^1.7.1",
|
||||
"dayjs": "^1.8.36",
|
||||
"polka": "next",
|
||||
"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: 'Works', href: '/works' },
|
||||
{ name: 'Projects', href: '/projects' },
|
||||
{ name: 'Blog', href: 'https://blog.nicco.io' },
|
||||
{ name: 'Blog', href: '/blog' },
|
||||
{ name: 'Contact', href: '/contact' },
|
||||
]
|
||||
|
||||
|
@ -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>
|
||||
|
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'
|
||||
|
||||
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>
|
||||
|
@ -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>
|
||||
|
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>
|
||||
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
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'
|
||||
|
||||
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)
|
||||
}
|
||||
|
@ -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>
|
||||
|
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,
|
||||
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;
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user