Favicon and tags/categories pages fix
|
|
@ -1,5 +1,6 @@
|
|||
import { metadata } from '@/app/metadata'
|
||||
import { getAllCategories, getCategoryBySlug, getPostsByCategory } from '@/lib/categories'
|
||||
import { dateFormatter } from '@/utils/time'
|
||||
import type { Metadata } from 'next'
|
||||
import Link from 'next/link'
|
||||
|
||||
|
|
@ -49,14 +50,35 @@ export default async function CategoryPage({ params }: CategoryPageProps) {
|
|||
|
||||
return (
|
||||
<main className="max-w-3xl 2xl:max-w-4xl mx-auto px-4 py-8 mb-8 lg:py-16 w-full">
|
||||
<h1>Category: {category}</h1>
|
||||
<ul>
|
||||
<div className="font-mono text-sm text-fg-dim mb-2">~/categories/{categorySlug}</div>
|
||||
|
||||
<div className="border-l border-border ml-1 mb-3">
|
||||
<span className="py-2 px-5 block font-bold group-hover:text-accent transition-colors capitalize">
|
||||
{category}
|
||||
</span>
|
||||
<ul className="border-l border-border ml-8 mb-3">
|
||||
{posts.map((post) => (
|
||||
<li key={post.slug}>
|
||||
<Link href={`/posts/${post.slug}`}>{post.title}</Link>
|
||||
<li key={post.slug} className="pl-5">
|
||||
<Link
|
||||
href={`/posts/${post.slug}`}
|
||||
className="group flex items-baseline justify-between gap-3 py-1.5 px-2 -ml-2 border-l-2 border-transparent hover:bg-accent/10 hover:border-accent transition-colors"
|
||||
>
|
||||
<span className="group-hover:text-accent transition-colors truncate">
|
||||
{post.title}
|
||||
</span>
|
||||
{post.date && (
|
||||
<time
|
||||
dateTime={new Date(post.date).toISOString()}
|
||||
className="text-sm whitespace-nowrap"
|
||||
>
|
||||
{dateFormatter.format(new Date(post.date))}
|
||||
</time>
|
||||
)}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ export default function CategoriesPage() {
|
|||
|
||||
return (
|
||||
<main className="max-w-3xl 2xl:max-w-4xl mx-auto px-4 py-8 mb-8 lg:py-16 w-full">
|
||||
<div className="text-sm text-fg-dim mb-2">~/categories</div>
|
||||
<div className="font-mono text-sm text-fg-dim mb-2">~/categories</div>
|
||||
|
||||
<ul className="border-l border-neutral-800 ml-1">
|
||||
<ul className="border-l border-border ml-1">
|
||||
{categoryNames.map((category) => {
|
||||
const categoryPosts = posts.filter((post) => post.category === category)
|
||||
|
||||
|
|
@ -49,10 +49,10 @@ export default function CategoriesPage() {
|
|||
<span className="font-bold group-hover:text-accent transition-colors">
|
||||
{category}
|
||||
</span>
|
||||
<span className="font-mono text-xs text-neutral-600">({categoryPosts.length})</span>
|
||||
<span className="text-xs text-fg">({categoryPosts.length})</span>
|
||||
</Link>
|
||||
|
||||
<ul className="border-l border-neutral-800 ml-3 mb-3">
|
||||
<ul className="border-l border-border ml-3 mb-3">
|
||||
{categoryPosts.map((post) => (
|
||||
<li key={post.slug} className="pl-5">
|
||||
<Link
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { metadata } from '@/app/metadata'
|
||||
import { getAllTags, getPostsByTag, getTagBySlug } from '@/lib/tags'
|
||||
import { dateFormatter } from '@/utils/time'
|
||||
import type { Metadata } from 'next'
|
||||
import Link from 'next/link'
|
||||
|
||||
|
|
@ -49,14 +50,35 @@ export default async function TagPage({ params }: TagPageProps) {
|
|||
|
||||
return (
|
||||
<main className="max-w-3xl 2xl:max-w-4xl mx-auto px-4 py-8 mb-8 lg:py-16 w-full">
|
||||
<h1>Tag: {tag}</h1>
|
||||
<ul>
|
||||
<div className="font-mono text-sm text-fg-dim mb-2">~/tags/{tagSlug}</div>
|
||||
|
||||
<div className="border-l border-border ml-1 mb-3">
|
||||
<span className="py-2 px-5 block font-bold group-hover:text-accent transition-colors capitalize">
|
||||
{tag}
|
||||
</span>
|
||||
<ul className="border-l border-border ml-8 mb-3">
|
||||
{posts.map((post) => (
|
||||
<li key={post.slug}>
|
||||
<Link href={`/posts/${post.slug}`}>{post.title}</Link>
|
||||
<li key={post.slug} className="pl-5">
|
||||
<Link
|
||||
href={`/posts/${post.slug}`}
|
||||
className="group flex items-baseline justify-between gap-3 py-1.5 px-2 -ml-2 border-l-2 border-transparent hover:bg-accent/10 hover:border-accent transition-colors"
|
||||
>
|
||||
<span className="group-hover:text-accent transition-colors truncate">
|
||||
{post.title}
|
||||
</span>
|
||||
{post.date && (
|
||||
<time
|
||||
dateTime={new Date(post.date).toISOString()}
|
||||
className="text-sm whitespace-nowrap"
|
||||
>
|
||||
{dateFormatter.format(new Date(post.date))}
|
||||
</time>
|
||||
)}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ export default function TagsPage() {
|
|||
|
||||
return (
|
||||
<main className="max-w-3xl 2xl:max-w-4xl mx-auto px-4 py-8 mb-8 lg:py-16 w-full">
|
||||
<div className="text-sm text-fg-dim mb-2">~/tags</div>
|
||||
<div className="font-mono text-sm text-fg-dim mb-2">~/tags</div>
|
||||
|
||||
<ul className="border-l border-neutral-800 ml-1">
|
||||
<ul className="border-l border-border ml-1">
|
||||
{tagNames.map((tag) => {
|
||||
const tagPosts = posts.filter((post) => post.tags && post.tags.includes(tag))
|
||||
|
||||
|
|
@ -49,10 +49,10 @@ export default function TagsPage() {
|
|||
<span className="font-bold group-hover:text-accent transition-colors capitalize">
|
||||
{tag}
|
||||
</span>
|
||||
<span className="font-mono text-xs text-neutral-600">({tagPosts.length})</span>
|
||||
<span className="text-xs text-fg">({tagPosts.length})</span>
|
||||
</Link>
|
||||
|
||||
<ul className="border-l border-neutral-800 ml-3 mb-3">
|
||||
<ul className="border-l border-border ml-3 mb-3">
|
||||
{tagPosts.map((post) => (
|
||||
<li key={post.slug} className="pl-5">
|
||||
<Link
|
||||
|
|
|
|||
BIN
app/apple-icon.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
app/favicon.ico
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 15 KiB |
1
app/icon0.svg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
app/icon1.png
Normal file
|
After Width: | Height: | Size: 857 B |
25
app/manifest.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import type { MetadataRoute } from 'next'
|
||||
|
||||
export default function manifest(): MetadataRoute.Manifest {
|
||||
return {
|
||||
name: 'Ephemeris',
|
||||
short_name: 'Ephemeris',
|
||||
icons: [
|
||||
{
|
||||
src: '/web-app-manifest-192x192.png',
|
||||
sizes: '192x192',
|
||||
type: 'image/png',
|
||||
purpose: 'maskable',
|
||||
},
|
||||
{
|
||||
src: '/web-app-manifest-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png',
|
||||
purpose: 'maskable',
|
||||
},
|
||||
],
|
||||
theme_color: '#ef1f1f',
|
||||
background_color: '#ef1f1f',
|
||||
display: 'standalone',
|
||||
}
|
||||
}
|
||||
|
|
@ -12,4 +12,9 @@ export const metadata: Metadata = {
|
|||
url: process.env.SITE_URL,
|
||||
siteName: 'Ephemeris',
|
||||
},
|
||||
appleWebApp: {
|
||||
title: 'Ephemeris',
|
||||
statusBarStyle: 'default',
|
||||
capable: true,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,9 +106,13 @@ export default async function Post({ params }: { params: Promise<{ slug: string
|
|||
<h2 className="text-lg font-bold">Tags</h2>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{meta.tags.map((tag) => (
|
||||
<span key={tag} className="bg-accent/20 text-accent px-3 py-1 rounded-full text-xs">
|
||||
<Link
|
||||
key={tag}
|
||||
href={`/tags/${slugify(tag)}`}
|
||||
className="bg-accent/20 text-accent px-3 py-1 rounded-full text-xs hover:bg-accent/30 transition-colors"
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export function ImageWrapper({ src, alt, isListing }: ImageWrapperProps) {
|
|||
<span className="text-xs text-fg-dim font-mono">~/{src}</span>
|
||||
</div>
|
||||
<Image
|
||||
src={`/${src}`}
|
||||
src={`/posts/${src}`}
|
||||
alt={alt ?? ''}
|
||||
width={isListing ? 400 : 800}
|
||||
height={isListing ? 240 : 400}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { metadata } from '@/app/metadata'
|
||||
import { NotepadText } from 'lucide-react'
|
||||
import { NavLinks } from '@/components/layout/NavLinks'
|
||||
import { siBluesky, siGithub, siMatrix, siTelegram, type SimpleIcon } from 'simple-icons'
|
||||
import { ExternalLink } from '@/components/ui/ExternalLink'
|
||||
import { getGitCommitHash } from '@/utils/git'
|
||||
import Image from 'next/image'
|
||||
|
||||
type SocialLink = {
|
||||
icon: SimpleIcon
|
||||
|
|
@ -38,7 +38,7 @@ export async function Sidebar() {
|
|||
<div className="sticky top-0 flex flex-col h-screen gap-4 py-4">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold mb-4 flex items-center gap-2">
|
||||
<NotepadText className="w-6 h-6" />
|
||||
<Image src="/logo.png" alt="Ephemeris Logo" width={32} height={32} />
|
||||
<span>{metadata.title!.toString()}</span>
|
||||
</h2>
|
||||
<ul className="space-y-2">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Folder, GitBranch, Home, Info, Rss, Tags } from 'lucide-react'
|
||||
import { ChartColumnStacked, GitBranch, Home, Info, Rss, Tags } from 'lucide-react'
|
||||
|
||||
type NavItem = {
|
||||
href: string
|
||||
|
|
@ -12,7 +12,11 @@ const navIconsClassName = 'w-6 h-6 lg:w-4 lg:h-4'
|
|||
export const navItems: NavItem[] = [
|
||||
{ href: '/', label: 'Home', icon: <Home className={navIconsClassName} /> },
|
||||
{ href: '/about', label: 'About', icon: <Info className={navIconsClassName} /> },
|
||||
{ href: '/categories', label: 'Categories', icon: <Folder className={navIconsClassName} /> },
|
||||
{
|
||||
href: '/categories',
|
||||
label: 'Categories',
|
||||
icon: <ChartColumnStacked className={navIconsClassName} />,
|
||||
},
|
||||
{ href: '/tags', label: 'Tags', icon: <Tags className={navIconsClassName} /> },
|
||||
{
|
||||
href: '/feed.xml',
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export function Post({ post, isLatest, showImageSlot }: PostProps) {
|
|||
{title}
|
||||
</Link>
|
||||
</h2>
|
||||
<p className="text-fg-dim font-mono text-sm">{description}</p>
|
||||
<p className="text-fg-dim text-sm">{description}</p>
|
||||
<div className="flex gap-2 items-center text-fg-dim text-xs font-mono mt-1">
|
||||
<time dateTime={publishedAt.toISOString()}>{dateFormatter.format(publishedAt)}</time>
|
||||
<span>·</span>
|
||||
|
|
|
|||
|
|
@ -39,8 +39,11 @@ export function TableOfContents({ items }: { items: TocItem[] }) {
|
|||
|
||||
return (
|
||||
<aside className="hidden lg:block w-80 2xl:w-100">
|
||||
<nav aria-label="Table of contents" className="sticky top-20">
|
||||
<h2 className="text-2xl font-bold mb-4">Table of Contents</h2>
|
||||
<nav
|
||||
aria-label="Table of contents"
|
||||
className="sticky top-12 border-l border-border h-fit pl-4 py-4"
|
||||
>
|
||||
<h2 className="text-xl font-bold mb-4">Table of Contents</h2>
|
||||
<ul className="space-y-1 text-sm">
|
||||
{items.map((item) => (
|
||||
<li key={item.id} className={indentByLevel[item.level] ?? 'pl-0'}>
|
||||
|
|
|
|||
BIN
public/logo.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
BIN
public/web-app-manifest-192x192.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
public/web-app-manifest-512x512.png
Normal file
|
After Width: | Height: | Size: 12 KiB |