mirror of
https://github.com/YouHaveTrouble/youhavetrouble.github.io.git
synced 2026-05-12 06:16:55 +00:00
switch to Astro
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
---
|
||||
import { ViewTransitions } from 'astro:transitions'
|
||||
import '../styles/fonts.css'
|
||||
import '../styles/global.css'
|
||||
|
||||
export interface Props {
|
||||
title: string
|
||||
description: string
|
||||
permalink: string
|
||||
}
|
||||
|
||||
const { title, description, permalink } = Astro.props
|
||||
const socialUrl = Astro.site.href + 'assets/yht_logo.png'
|
||||
---
|
||||
|
||||
<!-- Global Metadata -->
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
|
||||
<!-- Primary Meta Tags -->
|
||||
<title> {title} | YouHaveTrouble's place</title>
|
||||
<meta name="title" content={title} />
|
||||
<meta name="description" content={description} />
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content={permalink} />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:image" content={socialUrl} />
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:url" content={permalink} />
|
||||
<meta property="twitter:title" content={title} />
|
||||
<meta property="twitter:description" content={description} />
|
||||
<meta property="twitter:image" content={socialUrl} />
|
||||
|
||||
<ViewTransitions />
|
||||
|
||||
<!-- This is intentionally inlined to avoid FOUC -->
|
||||
<script is:inline>
|
||||
const root = document.documentElement
|
||||
const theme = localStorage.getItem('theme')
|
||||
if (
|
||||
theme === 'dark' ||
|
||||
(!theme && window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
) {
|
||||
root.classList.add('theme-dark')
|
||||
} else {
|
||||
root.classList.remove('theme-dark')
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,26 @@
|
||||
<div>
|
||||
<img src="/assets/yht_logo.png" alt="YouHaveTrouble's logo">
|
||||
<p>
|
||||
Hi, I'm <strong>Paweł</strong>, also known by <strong>YouHaveTrouble</strong> on the internet.
|
||||
I'a a full-stack web developer and minecraft plugin developer.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
div {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border-radius: 100px;
|
||||
display: block;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,19 @@
|
||||
<footer>
|
||||
<span>
|
||||
© {new Date().getFullYear()} Paweł "YouHaveTrouble" Michalewski.
|
||||
<br>
|
||||
Powered by Astro.
|
||||
</span>
|
||||
</footer>
|
||||
|
||||
<style>
|
||||
footer {
|
||||
color: var(--text-secondary);
|
||||
font-size: .8em;
|
||||
margin: 1em auto;
|
||||
max-width: 1400px;
|
||||
padding: 1em 2em;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
import Logo from './Logo.astro'
|
||||
import Nav from './Nav.astro'
|
||||
|
||||
const { current = '' } = Astro.props;
|
||||
---
|
||||
|
||||
<style>
|
||||
header {
|
||||
display: flex;
|
||||
margin: 0 auto;
|
||||
max-width: 1400px;
|
||||
padding: 2em;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<header>
|
||||
<Logo />
|
||||
<Nav current={current} />
|
||||
</header>
|
||||
@@ -0,0 +1,13 @@
|
||||
<style>
|
||||
|
||||
@media screen and (max-width: 520px) {
|
||||
img {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<a href="/">
|
||||
<img alt="Blog Logo" src="/assets/yht_logo.png" width="50px" height="50px" />
|
||||
</a>
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
import ThemeToggleButton from './ThemeToggleButton.svelte';
|
||||
const { current = '' } = Astro.props;
|
||||
---
|
||||
|
||||
<style>
|
||||
nav {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
font-family: var(--font-family-sans);
|
||||
font-weight: 700;
|
||||
justify-content: flex-end;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
padding: 10px 5px;
|
||||
display: block;
|
||||
position: relative;
|
||||
margin-left: 20px;
|
||||
min-width: 70px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
a:not(.selected) {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
a::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
transition: transform .3s ease;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: var(--text-secondary);
|
||||
transform: scaleX(0);
|
||||
}
|
||||
|
||||
a:hover::before,
|
||||
.selected::before {
|
||||
transform: scaleX(1);
|
||||
}
|
||||
|
||||
.selected::before {
|
||||
background: var(--primary-color);
|
||||
}
|
||||
|
||||
.theme-toggle-container {
|
||||
width: 75px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<nav>
|
||||
<a class={current === "" ? "selected" : ""} href='/'>home</a>
|
||||
<a class={current === "about" ? "selected" : ""} href='/about'>about</a>
|
||||
<a class={current === "blog" ? "selected" : ""} href='/blog'>blog</a>
|
||||
<div class="theme-toggle-container">
|
||||
<ThemeToggleButton client:load />
|
||||
</div>
|
||||
</nav>
|
||||
@@ -0,0 +1,65 @@
|
||||
<script>
|
||||
const rootEl = typeof document !== 'undefined' ? document.documentElement : null;
|
||||
const themes = ['light', 'dark'];
|
||||
let theme = ''
|
||||
|
||||
if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
|
||||
theme = localStorage.getItem('theme');
|
||||
} else if (typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
theme = 'dark';
|
||||
}
|
||||
|
||||
function handleChange(event) {
|
||||
theme = event.target.value;
|
||||
localStorage.setItem('theme', theme);
|
||||
}
|
||||
|
||||
$: if (rootEl && theme === 'light') {
|
||||
rootEl.classList.remove('theme-dark');
|
||||
} else if (rootEl && theme === 'dark') {
|
||||
rootEl.classList.add('theme-dark');
|
||||
}
|
||||
|
||||
const icons = [
|
||||
`<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>`,
|
||||
`<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
|
||||
</svg>`,
|
||||
];
|
||||
</script>
|
||||
|
||||
|
||||
<div class="theme-toggle">
|
||||
{#each themes as t, i}
|
||||
<label class={theme === t ? 'checked' : ''}>
|
||||
{@html icons[i]}
|
||||
<input
|
||||
type="radio"
|
||||
name="theme-toggle"
|
||||
checked={theme === t}
|
||||
value={t}
|
||||
title={`Use ${t} theme`}
|
||||
aria-label={`Use ${t} theme`}
|
||||
on:change={handleChange}
|
||||
/>
|
||||
</label>
|
||||
{/each}
|
||||
</div>
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="astro/client" />
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
import BaseHead from '../components/BaseHead.astro';
|
||||
import Header from '../components/Header.astro';
|
||||
import Footer from '../components/Footer.astro';
|
||||
|
||||
export interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
permalink: string;
|
||||
current?: string;
|
||||
}
|
||||
const { title, description, permalink, current } = Astro.props;
|
||||
---
|
||||
<html lang="en">
|
||||
<head>
|
||||
<BaseHead title={title} description={description} permalink={permalink} />
|
||||
</head>
|
||||
<body>
|
||||
<div class="layout">
|
||||
<Header current={current} />
|
||||
|
||||
<main>
|
||||
<slot />
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<style>
|
||||
.layout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100%;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
max-width: 1400px;
|
||||
padding: 1em 2em;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
|
||||
const title = 'About';
|
||||
const description = 'About your blog.';
|
||||
const permalink = `${Astro.site.href}about`;
|
||||
---
|
||||
|
||||
<BaseLayout title={title} description={description} permalink={permalink} current="about">
|
||||
<div class="container">
|
||||
<h1>About me</h1>
|
||||
|
||||
<p>My name is <strong>Paweł</strong>, but I'm better known as <strong>YouHaveTrouble</strong> on the internet.</p>
|
||||
<p>
|
||||
I currently work as a full-stack web developer. Technologies I usually use for my job are javascript, vuejs,
|
||||
typescript, sql. I also often actively research and learn about new technologies that could be used to improve my
|
||||
work.
|
||||
</p>
|
||||
<p>
|
||||
In my spare time I develop plugins for minecraft servers. This is a hobby that initially made me learn how to
|
||||
code. To this day I help maintain <a href="https://purpurmc.org">Purpur</a> server software along with its
|
||||
<a href="https://modrinth.com/plugin/purpurextras">official plugin</a>. List of plugins I currently support can be
|
||||
found <a href="https://modrinth.com/user/YouHaveTrouble/plugins">here</a>.
|
||||
</p>
|
||||
<p>
|
||||
My video game interests are mostly focused on narrative heavy games, but I also enjoy some ARPGs and roguelikes.
|
||||
You can see my full steam library <a href="https://steamcommunity.com/id/YouHaveTrouble/games/?tab=all">here</a>.
|
||||
Recommendations from my favourite games would include:
|
||||
</p>
|
||||
<ul>
|
||||
<li><a href="https://store.steampowered.com/app/420530/OneShot/">OneShot</a></li>
|
||||
<li><a href="https://store.steampowered.com/app/1150690/OMORI/">OMORI</a></li>
|
||||
<li><a href="https://store.steampowered.com/app/250900/The_Binding_of_Isaac_Rebirth/">The Binding of Isaac: Rebirth</a></li>
|
||||
<li><a href="https://store.steampowered.com/app/105600/Terraria/">Terraria</a></li>
|
||||
<li><a href="https://store.steampowered.com/app/582010/Monster_Hunter_World/">Monster Hunter: World</a></li>
|
||||
<li><a href="https://store.steampowered.com/app/238960/Path_of_Exile/">Path of Exile</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
padding-left: 1.5rem;
|
||||
margin-block: 0;
|
||||
}
|
||||
|
||||
ul li {
|
||||
margin-block: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import Bio from '../../components/Bio.astro';
|
||||
import getPostData from '../../utils/getPostData';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await Astro.glob('../../data/blog-posts/*.md');
|
||||
return posts.map(p => ({
|
||||
params: { slug: p.file.split('/').pop().split('.').shift() },
|
||||
props: { post: p },
|
||||
}));
|
||||
}
|
||||
|
||||
const { Content, frontmatter } = Astro.props.post;
|
||||
const { title, description, publishDate, tags } = frontmatter;
|
||||
const { slug, readingTime } = getPostData(Astro.props.post);
|
||||
const permalink = `${Astro.site.href}blog/${slug}`;
|
||||
---
|
||||
|
||||
<BaseLayout title={title} description={description} permalink={permalink} current="blog">
|
||||
<header>
|
||||
<p>{publishDate} ~ {readingTime}</p>
|
||||
<h1>{title}</h1>
|
||||
<div class="tags" style="justify-content: center">
|
||||
{tags.map(item => (
|
||||
<span class="tag">{item}</span>
|
||||
))}
|
||||
</div>
|
||||
<hr />
|
||||
</header>
|
||||
<div class="container">
|
||||
<article class="content">
|
||||
<Content />
|
||||
</article>
|
||||
<hr />
|
||||
<Bio />
|
||||
</div>
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
header {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
header h1 {
|
||||
margin-bottom: 0.7em;
|
||||
}
|
||||
|
||||
header p {
|
||||
color: var(--text-secondary);
|
||||
text-transform: uppercase;
|
||||
font-family: var(--font-family-sans);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
header hr {
|
||||
min-width: 100px;
|
||||
width: 30%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
|
||||
const title = 'Blog';
|
||||
const description = 'Latest articles.';
|
||||
const permalink = `${Astro.site.href}blog`;
|
||||
let allPosts = [];
|
||||
try {
|
||||
allPosts = await Astro.glob('../../data/blog-posts/*.md');
|
||||
} catch (error) {
|
||||
console.error('No blog posts found');
|
||||
}
|
||||
|
||||
allPosts = allPosts.sort((a, b) => new Date(b.frontmatter.publishDate).valueOf() - new Date(a.frontmatter.publishDate).valueOf());
|
||||
---
|
||||
|
||||
<BaseLayout title={title} description={description} permalink={permalink} current="blog">
|
||||
<div class="container">
|
||||
<h1>Blog</h1>
|
||||
{allPosts.length === 0 && <p>No posts as of yet, hop back later!</p>}
|
||||
{allPosts.map((post, index) => {
|
||||
const href = `/blog/${post.file.split('/').pop().split('.').shift()}`;
|
||||
return (
|
||||
<div>
|
||||
{ index !== 0 && <hr /> }
|
||||
<div class="post-item">
|
||||
<h2>
|
||||
<a href={href}>{post.frontmatter.title}</a>
|
||||
</h2>
|
||||
<div class="tags">
|
||||
{post.frontmatter.tags.map(item => (
|
||||
<span class="tag">{item}</span>
|
||||
))}
|
||||
</div>
|
||||
<p>{post.frontmatter.description}</p>
|
||||
<div class="post-item-footer">
|
||||
<span class="post-item-date">— {post.frontmatter.publishDate}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
h2,
|
||||
.post-item-footer {
|
||||
font-family: var(--font-family-sans);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.post-item-date {
|
||||
color: var(--text-secondary);
|
||||
text-align: left;
|
||||
text-transform: uppercase;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 60px auto;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,144 @@
|
||||
---
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
|
||||
const title = 'Home';
|
||||
const description = 'My little corner of the internet.';
|
||||
const permalink = Astro.site.href;
|
||||
---
|
||||
|
||||
<BaseLayout title={title} description={description} permalink={permalink}>
|
||||
<div class="home-container">
|
||||
<div class="home-copy">
|
||||
<h1>Welcome to my little corner of the interwebs</h1>
|
||||
<p>Feel free to check out what I got in store!</p>
|
||||
</div>
|
||||
|
||||
<div class="hero-socials-grid">
|
||||
<a href="https://github.com/YouHaveTrouble" class="social-link" target="_blank" rel="external">
|
||||
<img src="assets/icons/github.svg" alt="GitHub" draggable="false" loading="lazy">
|
||||
<span>GitHub</span>
|
||||
</a>
|
||||
<a href="https://discord.youhavetrouble.me" class="social-link" target="_blank" rel="external">
|
||||
<img src="assets/icons/discord.svg" alt="Discord" draggable="false" loading="lazy">
|
||||
<span>Discord</span>
|
||||
</a>
|
||||
<a href="https://ko-fi.com/youhavetrouble" class="social-link" target="_blank" rel="external">
|
||||
<img src="assets/icons/kofi.svg" alt="Ko-fi" draggable="false" loading="lazy">
|
||||
<span>Ko-fi</span>
|
||||
</a>
|
||||
<a href="https://steamcommunity.com/id/YouHavetrouble" class="social-link" target="_blank" rel="external">
|
||||
<img src="assets/icons/steam.svg" alt="Steam" draggable="false" loading="lazy">
|
||||
<span>Steam</span>
|
||||
</a>
|
||||
<a href="https://www.youtube.com/@YouHaveTrouble" class="social-link" target="_blank" rel="external">
|
||||
<img src="assets/icons/youtube.svg" alt="YouTube" draggable="false" loading="lazy">
|
||||
<span>YouTube</span>
|
||||
</a>
|
||||
<a href="https://modrinth.com/user/YouHaveTrouble" class="social-link" target="_blank" rel="external">
|
||||
<img src="assets/icons/modrinth.svg" alt="Modrinth" draggable="false" loading="lazy">
|
||||
<span>Modrinth</span>
|
||||
</a>
|
||||
<a href="https://wakatime.com/@YouHaveTrouble" class="social-link" target="_blank" rel="external">
|
||||
<img src="assets/icons/wakatime.svg" alt="WakaTime" draggable="false" loading="lazy">
|
||||
<span>WakaTime</span>
|
||||
</a>
|
||||
<a href="https://open.spotify.com/user/11144490753" class="social-link" target="_blank" rel="external">
|
||||
<img src="assets/icons/spotify.svg" alt="Spotify" draggable="false" loading="lazy">
|
||||
<span>Spotify</span>
|
||||
</a>
|
||||
<a href="https://www.linkedin.com/in/pawel-youhavetrouble-michalewski/" class="social-link" target="_blank" rel="external">
|
||||
<img src="assets/icons/linkedin.svg" alt="LinkedIn" draggable="false" loading="lazy">
|
||||
<span>LinkedIn</span>
|
||||
</a>
|
||||
<a href="mailto://contact@youhavetrouble.me" class="social-link" target="_blank" rel="external">
|
||||
<img src="assets/icons/email.svg" alt="Email" draggable="false" loading="lazy">
|
||||
<span>Email</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
.home-container {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
margin: 2em 0;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.home-copy {
|
||||
flex: 1;
|
||||
padding: 0 1em;
|
||||
}
|
||||
|
||||
.home-copy h1 {
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.5em;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.home-copy p {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
.hero-socials-grid {
|
||||
margin: 0 1em;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
max-width: min(100%, 450px);
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.hero-socials-grid a {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
width: 5.5rem;
|
||||
height: 5.5rem;
|
||||
text-decoration: none;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: transparent;
|
||||
padding: 0.5rem;
|
||||
gap: 0.25rem;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.hero-socials-grid a:hover {
|
||||
color: var(--text-main);
|
||||
border-color: var(--text-main);
|
||||
}
|
||||
|
||||
html:not(.theme-dark) .hero-socials-grid a img {
|
||||
filter: invert(0.8);
|
||||
}
|
||||
|
||||
.hero-socials-grid a img {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
p {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.home-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.home-copy {
|
||||
flex: 0;
|
||||
padding-bottom: 2em;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,36 @@
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Fira Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url(/assets/fonts/va9B4kDNxMZdWfMOD5VnLK3eRhf6Xl7Glw.woff2)
|
||||
format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
||||
U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Merriweather';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(/assets/fonts/u-440qyriQwlOrhSvowK_l5-fCZMdeX3rg.woff2)
|
||||
format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
||||
U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Merriweather';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url(/assets/fonts/u-4n0qyriQwlOrhSvowK_l52xwNZWMf6hPvhPQ.woff2)
|
||||
format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
||||
U+FEFF, U+FFFD;
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
:root {
|
||||
--background-body: #fff;
|
||||
--text-main: #36393b;
|
||||
--text-secondary: #6b6f72;
|
||||
--primary-color: #548e9b;
|
||||
--font-family-serif: Merriweather, serif;
|
||||
--font-family-sans: 'Fira Sans', sans-serif;
|
||||
}
|
||||
|
||||
:root.theme-dark {
|
||||
--background-body: #202122;
|
||||
--text-main: #fff;
|
||||
--text-secondary: #ccc;
|
||||
--primary-color: #548e9b;
|
||||
}
|
||||
|
||||
html {
|
||||
overflow-y: scroll;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
p {
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
@supports (scrollbar-gutter: stable) {
|
||||
html {
|
||||
overflow-y: auto;
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--font-family-serif);
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
background-color: var(--background-body);
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-family: var(--font-family-sans);
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: var(--font-family-serif);
|
||||
font-size: 4em;
|
||||
margin: 0 0 1em 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 1.6em 0 0 0;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
p,
|
||||
ul,
|
||||
ol {
|
||||
font-size: 1.3rem;
|
||||
line-height: 1.75em;
|
||||
margin: 1.2em 0;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-left: 2rem;
|
||||
-webkit-padding-start: 5%;
|
||||
-webkit-padding-end: 5%;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
li p {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
transition: color linear 0.15s;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
p a {
|
||||
text-decoration: none;
|
||||
box-shadow: inset 0 -0.12em 0 var(--primary-color);
|
||||
-webkit-transition: box-shadow 0.2s ease-in-out, color 0.2s ease-in-out;
|
||||
transition: box-shadow 0.2s ease-in-out, color 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
p a:hover {
|
||||
box-shadow: inset 0 -1.5em 0 var(--primary-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
hr {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
height: 10px;
|
||||
margin: 40px auto;
|
||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg width='20' height='10' viewBox='0 0 20 10' xmlns='http://www.w3.org/2000/svg' fill-rule='evenodd' clip-rule='evenodd' stroke-miterlimit='10'%3e%3cpath fill='none' d='M0 0h20v10H0z'/%3e%3cclipPath id='a'%3e%3cpath d='M0 0h20v10H0z'/%3e%3c/clipPath%3e%3cg clip-path='url(%23a)'%3e%3cpath d='M20 7.384c-4.999-.001-5-4.768-9.999-4.768C5 2.616 5 7.384 0 7.384' fill='none' stroke-width='3' stroke='%23548E9B'/%3e%3c/g%3e%3c/svg%3e");
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: 'SF Mono', menlo, inconsolata, monospace;
|
||||
font-size: calc(1em - 2px);
|
||||
color: #555;
|
||||
padding: 0.2em 0.4em;
|
||||
border-radius: 2px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
pre {
|
||||
border-radius: 8px !important;
|
||||
margin: 1.2em 0 !important;
|
||||
padding: 1.2em;
|
||||
}
|
||||
|
||||
pre code {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 4px solid #cccccc;
|
||||
font-size: 1.4em;
|
||||
font-style: italic;
|
||||
margin: 2rem 0;
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
blockquote p {
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
blockquote footer {
|
||||
font-size: 1.1rem;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
figure {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
-webkit-margin-start: 0;
|
||||
-webkit-margin-end: 0;
|
||||
margin: 0 0 3em 0;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
font-family: var(--font-family-sans);
|
||||
font-size: 1.125em;
|
||||
margin: 2em 0;
|
||||
}
|
||||
|
||||
th {
|
||||
border-bottom: 2px solid #cccccc;
|
||||
padding: 0.4em 0.8em;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 0.4em 0.8em;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 0 auto;
|
||||
max-width: 42em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content h1 {
|
||||
font-size: 3em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.theme-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
padding: 0.33em 0.67em;
|
||||
padding-top: 8px;
|
||||
margin-left: 10px;
|
||||
gap: 0.6em;
|
||||
border-radius: 99em;
|
||||
background-color: var(--theme-code-inline-bg);
|
||||
}
|
||||
|
||||
.theme-toggle > label:focus-within {
|
||||
outline: 2px solid transparent;
|
||||
box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white;
|
||||
}
|
||||
|
||||
.theme-toggle > label {
|
||||
color: var(--theme-code-inline-text);
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0.5;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.theme-toggle .checked {
|
||||
color: var(--theme-accent);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
input[name='theme-toggle'] {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem;
|
||||
padding-block: 0.2rem;
|
||||
}
|
||||
|
||||
span.tag {
|
||||
padding: 0.25rem;
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
span.tag::before {
|
||||
content: '#';
|
||||
}
|
||||
|
||||
@media (max-width: 1020px) {
|
||||
h1 {
|
||||
font-size: 3em;
|
||||
}
|
||||
|
||||
.content h1 {
|
||||
font-size: 2.4em;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
body {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
p,
|
||||
ul,
|
||||
ol {
|
||||
font-size: 1.2rem;
|
||||
margin: 1em 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import readingTime from 'reading-time'
|
||||
|
||||
type Post = {
|
||||
title: string
|
||||
file: string
|
||||
rawContent: () => string
|
||||
}
|
||||
|
||||
export default function getPostData(post: Post) {
|
||||
return {
|
||||
slug: post.file.split('/').pop().split('.').shift(),
|
||||
readingTime: readingTime(post.rawContent()).text,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user