view transition draft
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"_variables": {
|
"_variables": {
|
||||||
"lastUpdateCheck": 1738292575979
|
"lastUpdateCheck": 1739331457547
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
|
|
||||||
|
import portrait from '../img/portrait.jpg';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
size: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { size } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<Image
|
||||||
|
src={portrait}
|
||||||
|
alt="Illustrated portrait of a person with glasses and a beard, wearing a red and black plaid shirt. The background is a solid green color."
|
||||||
|
class="portrait"
|
||||||
|
width={`${size}`}
|
||||||
|
height={`${size}`}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.portrait {
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
border-radius: 200px;
|
||||||
|
}
|
||||||
|
a > svg {
|
||||||
|
transform: translateY(0.18rem);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -4,9 +4,9 @@ import { format, add } from 'date-fns';
|
|||||||
import CalendarIcon from '../img/svg/calendar.svg';
|
import CalendarIcon from '../img/svg/calendar.svg';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: String;
|
title: string;
|
||||||
date: Date;
|
date: Date;
|
||||||
slug?: String;
|
slug?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { title, date, slug } = Astro.props;
|
const { title, date, slug } = Astro.props;
|
||||||
|
|||||||
@@ -1,37 +1,54 @@
|
|||||||
---
|
---
|
||||||
|
import Avatar from './Avatar.astro';
|
||||||
const { pathname } = Astro.url;
|
const { pathname } = Astro.url;
|
||||||
|
|
||||||
interface Props {}
|
interface Props {}
|
||||||
|
|
||||||
interface NavLink {
|
interface NavLink {
|
||||||
label: string;
|
label: string;
|
||||||
icon: string;
|
|
||||||
path: string;
|
path: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const navLinks: NavLink[] = [
|
const navLinks: NavLink[] = [
|
||||||
{ label: 'Home', icon: 'person', path: '' },
|
{ label: 'Blog', path: 'blog' },
|
||||||
{ label: 'Blog', icon: 'pen', path: 'blog' },
|
{ label: 'Now', path: 'now' },
|
||||||
{ label: 'Now', icon: 'clock', path: 'now' },
|
{ label: 'Projects', path: 'projects' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const pathComponents = pathname.split('/').slice(1);
|
const pathComponents = pathname.split('/').slice(1);
|
||||||
---
|
---
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
<h1>ghall.blog</h1>
|
<div>
|
||||||
|
{
|
||||||
|
pathComponents[0] !== '' ? (
|
||||||
|
<a href="/" transition:name="my-avatar">
|
||||||
|
<Avatar size={60} />
|
||||||
|
</a>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
<nav>
|
<nav>
|
||||||
{
|
{
|
||||||
navLinks.map((link) => (
|
navLinks.map((link) => (
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a href={`/${link.path}`}>
|
||||||
href={`/${link.path}`}
|
|
||||||
class={pathComponents[0] === link.path ? 'selected' : null}
|
|
||||||
>
|
|
||||||
<span>{link.label}</span>
|
<span>{link.label}</span>
|
||||||
</a>
|
</a>
|
||||||
|
{pathComponents[0] === link.path ? (
|
||||||
|
<div class="underline" transition:name="menu-selection-indicator" />
|
||||||
|
) : null}
|
||||||
</li>
|
</li>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.underline {
|
||||||
|
height: 2px;
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--orange);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -9,10 +9,11 @@
|
|||||||
)
|
)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
const item = data.querySelector('item');
|
const item = data.querySelector('item');
|
||||||
|
console.log(item)
|
||||||
this.latestPost = {
|
this.latestPost = {
|
||||||
link: item.querySelector('link').textContent,
|
link: item.querySelector('link').textContent,
|
||||||
body: item.querySelector('description').textContent,
|
body: item.querySelector('description').textContent,
|
||||||
pubDate: item.querySelector('pubDate').textContent,
|
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@@ -27,7 +28,6 @@
|
|||||||
<h2>Latest Mastodon Post</h2>
|
<h2>Latest Mastodon Post</h2>
|
||||||
<p x-html="latestPost.body"></p>
|
<p x-html="latestPost.body"></p>
|
||||||
<a x-bind:href="latestPost.link" target="_blank">View Post</a>
|
<a x-bind:href="latestPost.link" target="_blank">View Post</a>
|
||||||
<small x-text="latestPost.pubDate"></small>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template x-if="!latestPost">
|
<template x-if="!latestPost">
|
||||||
|
|||||||
@@ -19,9 +19,7 @@ const { post } = Astro.props;
|
|||||||
const { data, slug } = post;
|
const { data, slug } = post;
|
||||||
---
|
---
|
||||||
|
|
||||||
<article>
|
<article transition:name={slug}>
|
||||||
<div>
|
<BlogHeader title={post.data.title} date={data.pubDate} slug={slug} />
|
||||||
<BlogHeader title={post.data.title} date={data.pubDate} slug={slug} />
|
<Tags tags={data.tags} />
|
||||||
<Tags tags={data.tags} />
|
|
||||||
</div>
|
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.7 MiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-arrow-left"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 12l14 0" /><path d="M5 12l6 6" /><path d="M5 12l6 -6" /></svg>
|
||||||
|
After Width: | Height: | Size: 386 B |
@@ -16,7 +16,7 @@ const title = Astro.props.title || Astro.props.frontmatter?.title || 'Unknown';
|
|||||||
---
|
---
|
||||||
|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en" transition:animate="none">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
@@ -29,16 +29,14 @@ const title = Astro.props.title || Astro.props.frontmatter?.title || 'Unknown';
|
|||||||
type="application/rss+xml"
|
type="application/rss+xml"
|
||||||
title="ghall.blog - RSS"
|
title="ghall.blog - RSS"
|
||||||
href={`${Astro.site}rss.xml`}
|
href={`${Astro.site}rss.xml`}
|
||||||
/><title>{`ghall.blog - ${title}`}</title></head
|
/><title>{`ghall.blog - ${title}`}</title>
|
||||||
>
|
<ClientRouter />
|
||||||
<ClientRouter />
|
</head>
|
||||||
<body class="layout-simple">
|
<body class="layout-simple" transition:animate="initial">
|
||||||
<Header />
|
<Header />
|
||||||
<main>
|
<main>
|
||||||
<slot />
|
<slot />
|
||||||
</main>
|
</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
import Layout from '@layouts/Layout.astro';
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
|
|
||||||
|
import DataGif from '../img/it-does-not-exist.gif';
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout title="Not Found">
|
||||||
|
<h2>404 - Page Not Found</h2>
|
||||||
|
<Image
|
||||||
|
class="gif"
|
||||||
|
src={DataGif}
|
||||||
|
alt="Data from Star Trek with the caption 'It does not exist'"
|
||||||
|
/>
|
||||||
|
</Layout>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h2 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gif {
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
layout: ../layouts/Layout.astro
|
|
||||||
title: Page Not Found
|
|
||||||
---
|
|
||||||
|
|
||||||
## 404 - Page not found!
|
|
||||||
|
|
||||||
You're trying to find a page that does not exist.
|
|
||||||
|
|
||||||
[Click here](/) to find your way home.
|
|
||||||
@@ -15,18 +15,18 @@ export async function getStaticPaths() {
|
|||||||
|
|
||||||
const { post } = Astro.props;
|
const { post } = Astro.props;
|
||||||
|
|
||||||
const { data } = post;
|
const { data, slug } = post;
|
||||||
|
|
||||||
const { Content } = await post.render();
|
const { Content } = await post.render();
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title={data.title}>
|
<Layout title={data.title}>
|
||||||
<BlogHeader title={data.title} date={data.pubDate} />
|
<article transition:name={slug}>
|
||||||
<article>
|
<BlogHeader title={data.title} date={data.pubDate} />
|
||||||
<Content />
|
<Content />
|
||||||
|
<a href="https://notbyai.fyi/">
|
||||||
|
<i class="not-by-ai"></i>
|
||||||
|
</a>
|
||||||
|
<Tags tags={data.tags} />
|
||||||
</article>
|
</article>
|
||||||
<a href="https://notbyai.fyi/">
|
|
||||||
<i class="not-by-ai"></i>
|
|
||||||
</a>
|
|
||||||
<Tags tags={data.tags} />
|
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ posts.sort(
|
|||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
posts.map(({ slug, data }) => (
|
posts.map(({ slug, data }) => (
|
||||||
<li>
|
<li transition:name={slug}>
|
||||||
<a href={`/posts/${slug}`}>{data.title}</a> -
|
<a href={`/posts/${slug}`}>{data.title}</a> -
|
||||||
<span>
|
<span>
|
||||||
{format(add(new Date(data.pubDate), { hours: 6 }), 'MMM do, y')}
|
{format(add(new Date(data.pubDate), { hours: 6 }), 'MMM do, y')}
|
||||||
@@ -60,3 +60,9 @@ posts.sort(
|
|||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
+7
-23
@@ -4,7 +4,7 @@ import { Image } from 'astro:assets';
|
|||||||
import { getCollection } from 'astro:content';
|
import { getCollection } from 'astro:content';
|
||||||
|
|
||||||
import Layout from '@layouts/Layout.astro';
|
import Layout from '@layouts/Layout.astro';
|
||||||
import LatestPost from '@components/LatestPost.astro';
|
import Avatar from '@components/Avatar.astro';
|
||||||
|
|
||||||
import portrait from '../img/portrait.jpg';
|
import portrait from '../img/portrait.jpg';
|
||||||
import MastodonIcon from '../img/svg/mastodon.svg';
|
import MastodonIcon from '../img/svg/mastodon.svg';
|
||||||
@@ -20,13 +20,9 @@ const latestPost = posts.sort(
|
|||||||
---
|
---
|
||||||
|
|
||||||
<Layout title="About">
|
<Layout title="About">
|
||||||
<Image
|
<div transition:name="my-avatar">
|
||||||
src={portrait}
|
<Avatar size={250} />
|
||||||
alt="Illustrated portrait of a person with glasses and a beard, wearing a red and black plaid shirt. The background is a solid green color."
|
</div>
|
||||||
class="portrait"
|
|
||||||
width="250"
|
|
||||||
height="250"
|
|
||||||
/>
|
|
||||||
<p>
|
<p>
|
||||||
My name is <strong>Graham</strong> (he/him), a full-stack web developer, and
|
My name is <strong>Graham</strong> (he/him), a full-stack web developer, and
|
||||||
tech enthusiast.
|
tech enthusiast.
|
||||||
@@ -42,8 +38,9 @@ const latestPost = posts.sort(
|
|||||||
development, and whatever else strikes my fancy.
|
development, and whatever else strikes my fancy.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Read my latest blog post, <a href={`blog/${latestPost.slug}`}
|
Read my latest blog post, <a
|
||||||
>{latestPost.data.title}</a
|
transition:name={latestPost.slug}
|
||||||
|
href={`blog/${latestPost.slug}`}>{latestPost.data.title}</a
|
||||||
>, from {new Date(latestPost.data.pubDate).toLocaleDateString()}.
|
>, from {new Date(latestPost.data.pubDate).toLocaleDateString()}.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
@@ -68,17 +65,4 @@ const latestPost = posts.sort(
|
|||||||
target="_blank">Natalia Vazquez</a
|
target="_blank">Natalia Vazquez</a
|
||||||
>.
|
>.
|
||||||
</p>
|
</p>
|
||||||
<LatestPost />
|
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<style>
|
|
||||||
.portrait {
|
|
||||||
display: block;
|
|
||||||
margin: auto;
|
|
||||||
margin-bottom: 26px;
|
|
||||||
border-radius: 200px;
|
|
||||||
}
|
|
||||||
a > svg {
|
|
||||||
transform: translateY(0.18rem);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -7,12 +7,6 @@ Hey there, this is my [/now page](https://nownownow.com/about)!
|
|||||||
|
|
||||||
_Last updated: February 4, 2025_
|
_Last updated: February 4, 2025_
|
||||||
|
|
||||||
## 🔨 Making
|
|
||||||
|
|
||||||
- This blog!
|
|
||||||
- [AutoDock](https://github.com/ghall89/AutoDock) - A Mac menubar utility that automatically hides and shows your dock based on the size of your connected display.
|
|
||||||
- [KeyStash](https://github.com/ghall89/KeyStash) - A native Mac app for managing registration codes for your apps, modelled on the feature from 1Password.
|
|
||||||
|
|
||||||
## 🎧 Listening
|
## 🎧 Listening
|
||||||
|
|
||||||
- [Tonight - Franz Ferdinand](https://music.apple.com/us/album/tonight/300683347)
|
- [Tonight - Franz Ferdinand](https://music.apple.com/us/album/tonight/300683347)
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
layout: ../layouts/Layout.astro
|
||||||
|
title: Projects
|
||||||
|
---
|
||||||
|
|
||||||
|
### [AutoDock](https://github.com/ghall89/AutoDock)
|
||||||
|
|
||||||
|
A MacOS menubar utility for automatically hiding and showing the Dock based on the screen size of the connected displays.
|
||||||
|
|
||||||
|
### [KeyStash](https://github.com/ghall89/KeyStash)
|
||||||
|
|
||||||
|
A MacOS application for managing software license keys for software purchased outside the Mac App Store.
|
||||||
|
|
||||||
|
### BGG Search (Raycast Extension) - Coming Soon!
|
||||||
|
|
||||||
|
A Raycast extension for searching [BoardGameGeek.com](https://boardgamegeek.com).
|
||||||
@@ -71,6 +71,7 @@ header {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
height: 120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
header > h1 > a {
|
header > h1 > a {
|
||||||
|
|||||||
Reference in New Issue
Block a user