i can't stop obsessing over the blog layout smdh
BIN
public/fonts/dotum-Regular.woff2
Normal file
BIN
public/fonts/dotumche-Regular.woff2
Normal file
BIN
src/assets/buttons.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 254 B |
Before Width: | Height: | Size: 252 B |
Before Width: | Height: | Size: 252 B |
Before Width: | Height: | Size: 255 B |
Before Width: | Height: | Size: 255 B |
Before Width: | Height: | Size: 255 B |
@ -10,8 +10,7 @@
|
|||||||
--sans-font: "Super Star", 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
|
--sans-font: "Super Star", 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
|
||||||
--arial-font: "Arial Pixel", Arial, Helvetica, sans-serif;
|
--arial-font: "Arial Pixel", Arial, Helvetica, sans-serif;
|
||||||
--pmd-font: "Wonder Mail", Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
|
--pmd-font: "Wonder Mail", Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
|
||||||
--mplus-10-font: "PixelMPlus 10", "MS Gothic", system-ui-ja, system-ui-zh-cn, system-ui-zh-tw, system-ui-zh-hk, system-ui-ko, sans-serif;
|
--dotum-font: "DotumChe", "Dotum", system-ui-ko, system-ui-ja, system-ui-zh-cn, system-ui-zh-tw, system-ui-zh-hk, monospace, sans-serif;
|
||||||
--mplus-12-font: "PixelMPlus 12", "MS Gothic", system-ui-ja, system-ui-zh-cn, system-ui-zh-tw, system-ui-zh-hk, system-ui-ko, sans-serif;
|
|
||||||
|
|
||||||
@media screen and (prefers-color-scheme: light) {
|
@media screen and (prefers-color-scheme: light) {
|
||||||
--bg-color: #e6f2ef;
|
--bg-color: #e6f2ef;
|
||||||
|
@ -2,12 +2,14 @@
|
|||||||
font-family: "Arial Pixel";
|
font-family: "Arial Pixel";
|
||||||
src: url("/fonts/pixearg.woff2") format("woff2");
|
src: url("/fonts/pixearg.woff2") format("woff2");
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
font-display: fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Arial Pixel";
|
font-family: "Arial Pixel";
|
||||||
src: url("/fonts/pixeab.woff2") format("woff2");
|
src: url("/fonts/pixeab.woff2") format("woff2");
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
font-display: fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -16,6 +18,18 @@
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Dotum";
|
||||||
|
src: url("/fonts/dotum-Regular.woff2") format("woff2");
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "DotumChe";
|
||||||
|
src: url("/fonts/dotumche-Regular.woff2") format("woff2");
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Kiwi Soda";
|
font-family: "Kiwi Soda";
|
||||||
src: url("/fonts/KiwiSoda.woff2") format("woff2");
|
src: url("/fonts/KiwiSoda.woff2") format("woff2");
|
||||||
|
@ -26,10 +26,17 @@ const { title, date, currently } = Astro.props;
|
|||||||
|
|
||||||
const blog = await getCollection("blog");
|
const blog = await getCollection("blog");
|
||||||
blog.length = Math.min(blog.length, 12);
|
blog.length = Math.min(blog.length, 12);
|
||||||
blog.sort((a, b) => a.data.pubDate!.valueOf() - b.data.pubDate!.valueOf());
|
blog.sort((a, b) => b.data.pubDate!.valueOf() - a.data.pubDate!.valueOf());
|
||||||
---
|
---
|
||||||
<Layout {title}>
|
<Layout {title}>
|
||||||
<slot slot="head" name="head" />
|
<Fragment slot="head">
|
||||||
|
<link rel="preload" href={outerBBS.src} as="image" />
|
||||||
|
<link rel="preload" href={innerBBS.src} as="image" />
|
||||||
|
<link rel="preload" href={sideBBS.src} as="image" />
|
||||||
|
<link rel="preload" href="/fonts/pixearg.woff2" as="font" />
|
||||||
|
<link rel="preload" href="/fonts/pixeab.woff2" as="font" />
|
||||||
|
<slot name="head" />
|
||||||
|
</Fragment>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
@ -143,15 +150,19 @@ blog.sort((a, b) => a.data.pubDate!.valueOf() - b.data.pubDate!.valueOf());
|
|||||||
--border-4: #88aabb;
|
--border-4: #88aabb;
|
||||||
--border-5: #99bbcc;
|
--border-5: #99bbcc;
|
||||||
--border-6: #bbccdd;
|
--border-6: #bbccdd;
|
||||||
|
--normal-color: #335577;
|
||||||
|
--active-color: #aa0033;
|
||||||
|
--active-border: #442266;
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
h1 { font: bold 1rem var(--arial-font); }
|
h1 { font: bold 1rem var(--arial-font); }
|
||||||
h2 {
|
h2 {
|
||||||
font: normal 1.5rem var(--mplus-12-font);
|
font: normal 1rem var(--dotum-font);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
main {
|
main {
|
||||||
font: 1rem var(--arial-font);
|
font: 1rem var(--arial-font);
|
||||||
|
letter-spacing: 1px;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto minmax(auto, 75ch);
|
grid-template-columns: auto minmax(auto, 75ch);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -211,8 +222,7 @@ blog.sort((a, b) => a.data.pubDate!.valueOf() - b.data.pubDate!.valueOf());
|
|||||||
|
|
||||||
.item {
|
.item {
|
||||||
position: relative;
|
position: relative;
|
||||||
font-family: var(--mplus-10-font);
|
font: bold 1em var(--dotum-font);
|
||||||
font-size: 1.25rem; /* this should be 20px */
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -225,6 +235,17 @@ blog.sort((a, b) => a.data.pubDate!.valueOf() - b.data.pubDate!.valueOf());
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
~ .link {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
/* max-width: 19ch; */
|
||||||
|
|
||||||
|
@media screen and (max-width: 76em) {
|
||||||
|
max-width: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,7 +290,6 @@ blog.sort((a, b) => a.data.pubDate!.valueOf() - b.data.pubDate!.valueOf());
|
|||||||
|
|
||||||
article {
|
article {
|
||||||
display: flex;
|
display: flex;
|
||||||
letter-spacing: 1px;
|
|
||||||
border: 2px solid var(--border-0);
|
border: 2px solid var(--border-0);
|
||||||
border-image: var(--outerBorder) 19 9 38 11 fill / 38px 18px 76px 22px;
|
border-image: var(--outerBorder) 19 9 38 11 fill / 38px 18px 76px 22px;
|
||||||
background-color: var(--bg-3);
|
background-color: var(--bg-3);
|
||||||
@ -286,7 +306,9 @@ blog.sort((a, b) => a.data.pubDate!.valueOf() - b.data.pubDate!.valueOf());
|
|||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font: normal 1.5rem var(--mplus-12-font);
|
display: grid;
|
||||||
|
place-content: center;
|
||||||
|
font: normal 1.25em var(--dotum-font);
|
||||||
background-color: var(--bg-2);
|
background-color: var(--bg-2);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
}
|
}
|
||||||
@ -316,9 +338,10 @@ blog.sort((a, b) => a.data.pubDate!.valueOf() - b.data.pubDate!.valueOf());
|
|||||||
border-color: var(--bg-2) var(--bg-2) var(--bg-1) var(--bg-1);
|
border-color: var(--bg-2) var(--bg-2) var(--bg-1) var(--bg-1);
|
||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
|
|
||||||
time, .section {
|
time {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,6 +368,19 @@ blog.sort((a, b) => a.data.pubDate!.valueOf() - b.data.pubDate!.valueOf());
|
|||||||
|
|
||||||
p { margin-block: 1lh; }
|
p { margin-block: 1lh; }
|
||||||
a, del, s { text-decoration-thickness: 2px; }
|
a, del, s { text-decoration-thickness: 2px; }
|
||||||
|
a {
|
||||||
|
color: var(--normal-color);
|
||||||
|
|
||||||
|
&:visited {
|
||||||
|
color: var(--active-border);
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
color: var(--active-color);
|
||||||
|
}
|
||||||
|
&:active, &:focus {
|
||||||
|
color: var(--normal-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@supports not (margin-trim: block) {
|
@supports not (margin-trim: block) {
|
||||||
:first-child { margin-block-start: 0; }
|
:first-child { margin-block-start: 0; }
|
||||||
|
@ -2,13 +2,7 @@
|
|||||||
import Blog from '@/layouts/Blog.astro';
|
import Blog from '@/layouts/Blog.astro';
|
||||||
import type { GetStaticPaths } from 'astro';
|
import type { GetStaticPaths } from 'astro';
|
||||||
import { getCollection, render } from 'astro:content';
|
import { getCollection, render } from 'astro:content';
|
||||||
|
import buttons from "$/buttons.png";
|
||||||
import leftNormal from "$/left-normal.png";
|
|
||||||
import leftHover from "$/left-hover.png";
|
|
||||||
import leftActive from "$/left-active.png";
|
|
||||||
import rightNormal from "$/right-normal.png";
|
|
||||||
import rightHover from "$/right-hover.png";
|
|
||||||
import rightActive from "$/right-active.png";
|
|
||||||
|
|
||||||
export const getStaticPaths = (async () => {
|
export const getStaticPaths = (async () => {
|
||||||
const blog = await getCollection("blog");
|
const blog = await getCollection("blog");
|
||||||
@ -30,30 +24,37 @@ const next = current === 0 ? undefined : blog[current - 1];
|
|||||||
<Blog title={entry.data.title!} date={entry.data.pubDate!} currently={entry.data.currently}>
|
<Blog title={entry.data.title!} date={entry.data.pubDate!} currently={entry.data.currently}>
|
||||||
<Fragment slot="head">
|
<Fragment slot="head">
|
||||||
<meta name="description" content={entry.body?.substring(0, 150) + "…"}>
|
<meta name="description" content={entry.body?.substring(0, 150) + "…"}>
|
||||||
|
<link rel="preload" href={buttons.src} as="image" />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
|
||||||
<Content />
|
<Content />
|
||||||
|
|
||||||
{(previous || next) && (
|
{(previous || next) && (
|
||||||
<div id="blog-pagination" slot="pagination">
|
<footer id="blog-pagination" slot="pagination">
|
||||||
{previous && (
|
{previous && (
|
||||||
<a id="previous" aria-label="previous post" href={`/blog/${previous.id}`}>
|
<a id="previous" aria-label="go to previous post" href={`/blog/${previous.id}`}>
|
||||||
<img class="arrow" src={leftNormal.src} alt="" />
|
<div class="arrow" />
|
||||||
{previous.data.title}
|
<div class="title">
|
||||||
|
<span>{previous.data.title}</span>
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{next && (
|
{next && (
|
||||||
<a id="next" aria-label="next post" href={`/blog/${next.id}`}>
|
<a id="next" aria-label="go to next post" href={`/blog/${next.id}`}>
|
||||||
{next.data.title}
|
<div class="title">
|
||||||
<img class="arrow" src={rightNormal.src} alt="" />
|
<span>{next.data.title}</span>
|
||||||
|
</div>
|
||||||
|
<div class="arrow" />
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
</div>
|
</footer>
|
||||||
)}
|
)}
|
||||||
</Blog>
|
</Blog>
|
||||||
|
|
||||||
<style define:vars={{ leftNormal: `url(${leftNormal.src})`, leftHover: `url(${leftHover.src})`, leftActive: `url(${leftActive.src})`, rightNormal: `url(${rightNormal.src})`, rightHover: `url(${rightHover.src})`, rightActive: `url(${rightActive.src})` }}>
|
<style define:vars={{ buttons: `url(${buttons.src})` }}>
|
||||||
#blog-pagination {
|
#blog-pagination {
|
||||||
|
margin: 1rem 0;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
@ -61,33 +62,87 @@ const next = current === 0 ? undefined : blog[current - 1];
|
|||||||
.arrow {
|
.arrow {
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
|
background: var(--buttons) no-repeat top left;
|
||||||
}
|
}
|
||||||
|
|
||||||
#previous {
|
#previous {
|
||||||
grid-column: 1 / 2;
|
grid-column: 1 / 2;
|
||||||
justify-self: left;
|
justify-self: left;
|
||||||
|
|
||||||
.arrow { content: var(--leftNormal) var(--leftHover) var(--leftActive); }
|
.arrow { background-position: 0 0; }
|
||||||
&:hover .arrow { content: var(--leftHover); }
|
&:hover .arrow { background-position: -36px 0; }
|
||||||
&:active .arrow, &:focus .arrow { content: var(--leftActive); }
|
&:active .arrow, &:focus .arrow { background-position: -72px 0; }
|
||||||
|
|
||||||
|
.title {
|
||||||
|
border-left: none;
|
||||||
|
margin-left: -2px;
|
||||||
|
padding-left: calc(0.5em + 2px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#next {
|
#next {
|
||||||
grid-column: 2 / -1;
|
grid-column: 2 / -1;
|
||||||
justify-self: right;
|
justify-self: right;
|
||||||
|
|
||||||
.arrow { content: var(--rightNormal) var(--rightHover) var(--rightActive); }
|
.arrow { background-position: -108px 0; }
|
||||||
&:hover .arrow { content: var(--rightHover); }
|
&:hover .arrow { background-position: -144px 0; }
|
||||||
&:active .arrow, &:focus .arrow { content: var(--rightActive); }
|
&:active .arrow, &:focus .arrow { background-position: -180px 0; }
|
||||||
|
|
||||||
|
.title {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
border-right: none;
|
||||||
|
margin-right: -2px;
|
||||||
|
padding-right: calc(0.5em + 2px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row wrap;
|
flex-flow: row wrap;
|
||||||
align-items: center;
|
align-items: stretch;
|
||||||
gap: 2px;
|
font: bold larger var(--dotum-font);
|
||||||
color: var(--bg-0);
|
color: var(--normal-color);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
display: grid;
|
||||||
|
place-content: center;
|
||||||
|
padding: 0 0.5em;
|
||||||
|
background-color: var(--bg-7);
|
||||||
|
border: 2px solid var(--border-1);
|
||||||
|
box-shadow:
|
||||||
|
inset 2px 2px 0 0 var(--bg-0),
|
||||||
|
inset 4px 4px 0 0 var(--bg-5),
|
||||||
|
inset -2px -2px 0 0 var(--border-5),
|
||||||
|
inset -4px -4px 0 0 var(--border-6);
|
||||||
|
|
||||||
|
@media screen and (468px > width) {
|
||||||
|
> span {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
max-width: calc(12ch + 1em);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--active-color);
|
||||||
|
.title { border-color: var(--active-border); }
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active, &:focus {
|
||||||
|
color: var(--normal-color);
|
||||||
|
.title {
|
||||||
|
border-color: var(--border-1);
|
||||||
|
box-shadow:
|
||||||
|
inset -2px -2px 0 0 var(--bg-0),
|
||||||
|
inset -4px -4px 0 0 var(--bg-5),
|
||||||
|
inset 2px 2px 0 0 var(--border-5),
|
||||||
|
inset 4px 4px 0 0 var(--border-6);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,16 +1,14 @@
|
|||||||
---
|
---
|
||||||
import Layout from "@/layouts/Layout.astro";
|
import Layout from "@/layouts/Layout.astro";
|
||||||
|
import formatDate from "@/utils/formatDate";
|
||||||
import { getCollection } from "astro:content";
|
import { getCollection } from "astro:content";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import utc from "dayjs/plugin/utc";
|
|
||||||
|
|
||||||
const blog = await getCollection("blog");
|
const blog = await getCollection("blog");
|
||||||
const sorted = Object.groupBy(blog, ({ data }) => data.pubDate!.getMonth());
|
const sorted = Object.groupBy(blog, ({ data }) => data.pubDate!.getMonth());
|
||||||
|
|
||||||
dayjs.extend(utc);
|
function getMonth(id: number): string {
|
||||||
const getMonth = (id: number) => {
|
|
||||||
let date = new Date();
|
let date = new Date();
|
||||||
date.setDate(1);
|
|
||||||
date.setMonth(id);
|
date.setMonth(id);
|
||||||
return dayjs(date).format("MMMM");
|
return dayjs(date).format("MMMM");
|
||||||
}
|
}
|
||||||
@ -27,8 +25,8 @@ const getMonth = (id: number) => {
|
|||||||
<ul>
|
<ul>
|
||||||
{entry[1]?.sort((a, b) => a.data.pubDate!.valueOf() - b.data.pubDate!.valueOf()).map(post => (
|
{entry[1]?.sort((a, b) => a.data.pubDate!.valueOf() - b.data.pubDate!.valueOf()).map(post => (
|
||||||
<li>
|
<li>
|
||||||
<time datetime={dayjs(post.data.pubDate).utc(true).toISOString()}>
|
<time datetime={formatDate(post.data.pubDate!, true)}>
|
||||||
{dayjs(post.data.pubDate).utc(true).format("MMMM DD, YYYY")}
|
{formatDate(post.data.pubDate!)}
|
||||||
</time>
|
</time>
|
||||||
<a href={`/blog/${post.id}`}>{post.data.title}</a>
|
<a href={`/blog/${post.id}`}>{post.data.title}</a>
|
||||||
</li>
|
</li>
|
||||||
|