diff --git a/src/App.tsx b/src/App.tsx
index 28b1af5..3b8f2ac 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -8,6 +8,12 @@ import {
} from "./config";
import { arweaveUrl, getReadableDate, loadManifest, loadPostContent } from "./lib";
import type { Frontmatter, ManifestPost } from "./types";
+import load1 from "./load1.png";
+import load2 from "./load2.png";
+import load3 from "./load3.png";
+import load4 from "./load4.png";
+import load5 from "./load5.png";
+import load6 from "./load6.png";
type LoadState = "idle" | "loading" | "error";
@@ -21,6 +27,9 @@ type MetaInput = {
modifiedTime?: string;
};
+const LOADER_FRAMES = [load1, load2, load3, load4, load5, load6];
+const FORCE_LOADER_PREVIEW = false;
+
const toAbsoluteUrl = (path = "/"): string => new URL(path, BLOG_SITE_URL).toString();
const setMetaTag = (attribute: "name" | "property", key: string, content?: string): void => {
@@ -91,9 +100,19 @@ const usePageMetadata = ({
};
function BlisterLoader() {
+ const [frame, setFrame] = useState(0);
+
+ useEffect(() => {
+ const timer = window.setInterval(() => {
+ setFrame((value) => (value + 1) % LOADER_FRAMES.length);
+ }, 70);
+
+ return () => window.clearInterval(timer);
+ }, []);
+
return (
-
+
);
}
@@ -137,18 +156,23 @@ function App() {
return (
+ {FORCE_LOADER_PREVIEW ? (
+
+ ) : (
} />
+ )}
);
@@ -341,9 +366,15 @@ function PostPage({
{updatedDate && Updated {updatedDate}}
{post.readingTime && {post.readingTime} min read}
{post.wordCount && {post.wordCount} words}
+ {post.postTxId.slice(0, 8)}...
[permalink]
+
+
+ [arweave]
+
+
{bannerTxId && (
diff --git a/src/favicon.ico b/src/favicon.ico
index 18dbc2d..24ac122 100644
Binary files a/src/favicon.ico and b/src/favicon.ico differ
diff --git a/src/load1.png b/src/load1.png
new file mode 100644
index 0000000..2ad15bc
Binary files /dev/null and b/src/load1.png differ
diff --git a/src/load2.png b/src/load2.png
new file mode 100644
index 0000000..53c853a
Binary files /dev/null and b/src/load2.png differ
diff --git a/src/load3.png b/src/load3.png
new file mode 100644
index 0000000..166f331
Binary files /dev/null and b/src/load3.png differ
diff --git a/src/load4.png b/src/load4.png
new file mode 100644
index 0000000..54a2553
Binary files /dev/null and b/src/load4.png differ
diff --git a/src/load5.png b/src/load5.png
new file mode 100644
index 0000000..f1157bb
Binary files /dev/null and b/src/load5.png differ
diff --git a/src/load6.png b/src/load6.png
new file mode 100644
index 0000000..22718e7
Binary files /dev/null and b/src/load6.png differ
diff --git a/src/styles.css b/src/styles.css
index 8cb14a4..3162db0 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -1,23 +1,39 @@
+@import url("https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500&display=swap");
+
:root {
- color: #0a0a0a;
+ color: #101010;
background: #ffffff;
- font-family: "IBM Plex Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
- line-height: 1.6;
+ font-family: "DM Sans", sans-serif;
+ line-height: 1.55;
+ --site-max-width: 760px;
--brand-red: #f60000;
--brand-purple: #9611ff;
--brand-blue: #86dafe;
--brand-yellow: #fee55f;
--brand-green: #33f22f;
+ --line: #121212;
+ --line-soft: #d8d8d8;
+ --muted: #585858;
+ --accent: #0072c8;
}
* {
box-sizing: border-box;
+ border-radius: 0;
+}
+
+html,
+body,
+#root {
+ min-height: 100%;
}
body {
margin: 0;
background: #ffffff;
color: #111111;
+ font-family: "DM Sans", sans-serif;
+ font-weight: 400;
}
a {
@@ -26,21 +42,32 @@ a {
text-underline-offset: 3px;
}
+a:hover {
+ color: var(--accent);
+}
+
.page {
min-height: 100vh;
- padding: 24px;
+ width: min(var(--site-max-width), 100% - 48px);
+ margin: 0 auto;
+ padding: 0 0 48px;
}
.header {
- border-bottom: 2px solid #111111;
- padding-bottom: 14px;
- margin-bottom: 28px;
+ border-bottom: 1px solid var(--line);
+}
+
+.header-row {
+ display: flex;
+ align-items: center;
+ min-height: 72px;
+ padding: 0 24px;
}
.brand {
- font-family: "IBM Plex Mono", "SFMono-Regular", Menlo, Consolas, monospace;
+ font-family: "DM Sans", sans-serif;
font-size: 1.3rem;
- font-weight: 600;
+ font-weight: 500;
letter-spacing: 0.08em;
text-decoration: none;
display: inline-flex;
@@ -87,12 +114,14 @@ a {
}
.content {
- max-width: 860px;
- margin: 0 auto;
+ max-width: 100%;
}
.status {
- font-size: 1rem;
+ margin: 0;
+ padding: 24px;
+ border-top: 1px solid var(--line);
+ font-size: 0.95rem;
}
.loader-screen {
@@ -101,58 +130,39 @@ a {
place-items: center;
}
-.loader-square {
- width: 22px;
- height: 22px;
- background: var(--brand-red);
- animation: blister-flicker 180ms steps(1, end) infinite;
-}
-
-@keyframes blister-flicker {
- 0% {
- background: var(--brand-red);
- }
- 20% {
- background: var(--brand-purple);
- }
- 40% {
- background: var(--brand-blue);
- }
- 60% {
- background: var(--brand-yellow);
- }
- 80% {
- background: var(--brand-green);
- }
- 100% {
- background: var(--brand-red);
- }
+.loader-frame {
+ display: block;
+ width: min(45px, 11vw);
+ height: auto;
+ image-rendering: pixelated;
+ border-radius: 8px;
}
.index {
- display: grid;
- gap: 28px;
+ border-top: 0;
+}
+
+.post-card {
+ padding: 22px 24px 26px;
+ border-bottom: 1px solid var(--line-soft);
+}
+
+.post-card-featured {
+ border-bottom: 1px solid var(--line-soft);
+ background: linear-gradient(180deg, #ffffff 0%, #fcfcfc 100%);
}
.index-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
- column-gap: 28px;
- row-gap: 28px;
}
-.post-card {
- padding-top: 0;
+.index-grid .post-card {
+ border-bottom: 0;
}
-.index-grid .post-card:nth-child(n + 3) {
- border-top: 1px solid #111111;
- padding-top: 18px;
-}
-
-.post-card-featured {
- border-top: 0;
- padding-top: 0;
+.index-grid .post-card:nth-child(odd) {
+ border-right: 0;
}
.banner-link {
@@ -164,36 +174,43 @@ a {
display: block;
width: 100%;
height: auto;
- border: 1px solid #111111;
+ border: 1px solid var(--line);
}
.post-title-link {
text-decoration: none;
}
+.post-title-link:hover .post-title {
+ color: var(--accent);
+}
+
.post-title {
margin: 0;
- font-size: 1.8rem;
- line-height: 1.2;
+ font-size: clamp(1.32rem, 2.15vw, 1.7rem);
+ font-weight: 500;
+ line-height: 1.18;
+ letter-spacing: -0.02em;
}
.post-description {
- margin: 10px 0 12px;
- font-size: 1.04rem;
+ margin: 12px 0 14px;
+ font-size: 0.97rem;
+ color: #222222;
}
.meta-row {
display: flex;
flex-wrap: wrap;
gap: 0;
- font-family: "IBM Plex Mono", "SFMono-Regular", Menlo, Consolas, monospace;
- font-size: 0.86rem;
+ font-size: 0.82rem;
+ color: var(--muted);
}
.meta-row > span + span {
position: relative;
- margin-left: 14px;
- padding-left: 14px;
+ margin-left: 12px;
+ padding-left: 12px;
}
.meta-row > span + span::before {
@@ -203,51 +220,61 @@ a {
top: 50%;
width: 6px;
height: 1px;
- background: #111111;
+ background: #7d7d7d;
transform: translateY(-50%);
}
-.post-meta-row > span + span::before {
- content: "|";
- width: auto;
- height: auto;
- background: none;
- top: 0;
- transform: none;
-}
-
.post {
- max-width: 760px;
+ border-top: 0;
}
-.post-topline {
- margin-bottom: 16px;
-}
-
-.home-link {
- text-decoration: none;
- border-bottom: 1px solid #111111;
+.post-header {
+ max-width: 100%;
+ margin: 0;
+ padding: 24px 24px 0;
+ border-bottom: 0;
}
.post-header h1 {
margin: 0;
- line-height: 1.15;
- font-size: clamp(2rem, 6vw, 3.4rem);
+ line-height: 1.07;
+ font-size: clamp(2rem, 5vw, 3rem);
+ font-weight: 500;
+ letter-spacing: -0.03em;
+ max-width: 26ch;
}
.post-header p {
- margin: 12px 0;
- font-size: 1.06rem;
+ margin: 14px 0 0;
+ max-width: 70ch;
+ font-size: 1rem;
+ color: #1b1b1b;
+}
+
+.post-meta-row {
+ margin-top: 14px;
+}
+
+.post-meta-row a {
+ color: #1f1f1f;
}
.post-hero {
- margin-top: 24px;
+ max-width: 100%;
+ margin: 0;
+ padding: 24px 24px 0;
+ border-bottom: 0;
+}
+
+.post-hero .post-banner {
+ width: 100%;
+ margin: 0;
}
.article {
- margin-top: 32px;
- border-top: 1px solid #111111;
- padding-top: 24px;
+ max-width: 100%;
+ margin: 0;
+ padding: 30px 24px 52px;
}
.article > *:first-child {
@@ -257,56 +284,92 @@ a {
.article h2,
.article h3,
.article h4 {
- margin-top: 1.9em;
- line-height: 1.25;
+ margin-top: 1.6em;
+ margin-bottom: 0.55em;
+ line-height: 1.2;
+ font-weight: 500;
+}
+
+.article p,
+.article li,
+.article blockquote {
+ font-size: 1.04rem;
+}
+
+.article ul,
+.article ol {
+ padding-left: 1.3rem;
+}
+
+.article a {
+ color: var(--accent);
}
.article pre {
- border: 1px solid #111111;
+ border: 1px solid var(--line);
padding: 14px;
overflow: auto;
- background: #ffffff;
+ background: #f7f7f7;
+ font-size: 0.9rem;
}
.article code {
- font-family: "IBM Plex Mono", "SFMono-Regular", Menlo, Consolas, monospace;
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
+ "Courier New", monospace;
+ font-size: 0.9em;
+}
+
+.article pre,
+.article kbd,
+.article samp {
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
+ "Courier New", monospace;
}
.article blockquote {
- margin-left: 0;
- padding-left: 16px;
- border-left: 2px solid #111111;
+ margin: 1.2em 0;
+ padding: 0 0 0 14px;
+ border-left: 2px solid var(--line);
+ color: #292929;
}
.article img {
max-width: 100%;
height: auto;
+ border: 0;
}
-@media (max-width: 740px) {
+@media (max-width: 860px) {
.page {
- padding: 16px;
+ width: 100%;
+ border-left: 0;
+ border-right: 0;
+ padding-top: 0;
}
- .index {
- grid-template-columns: 1fr;
+ .header-row {
+ min-height: 64px;
+ padding: 0 16px;
+ }
+
+ .post-card,
+ .post-header,
+ .post-hero,
+ .article,
+ .status {
+ padding-left: 16px;
+ padding-right: 16px;
}
.index-grid {
grid-template-columns: 1fr;
}
- .index-grid .post-card:nth-child(n + 3) {
- border-top: 0;
- padding-top: 0;
- }
-
- .index-grid .post-card + .post-card {
- border-top: 1px solid #111111;
- padding-top: 18px;
+ .index-grid .post-card:nth-child(odd) {
+ border-right: 0;
}
.post-title {
- font-size: 1.45rem;
+ font-size: 1.38rem;
}
}
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/src/vite-env.d.ts
@@ -0,0 +1 @@
+///