prod update

This commit is contained in:
echo 2026-02-23 05:54:35 +01:00
parent 3af4b92e1b
commit 3b827a90ac
13 changed files with 128 additions and 117 deletions

View File

@ -25,7 +25,8 @@ export function ArticleTicker() {
{articles.map((article, index) => ( {articles.map((article, index) => (
<Link <Link
key={`${article.id}-${index}`} key={`${article.id}-${index}`}
to={`/articles/${article.id}`} to="/articles/$id"
params={{ id: article.id }}
className="font-body text-sm uppercase tracking-wider text-background/80 hover:text-accent hover:bg-background/10 inline-block px-6 py-1 border-r border-background/20 transition-colors" className="font-body text-sm uppercase tracking-wider text-background/80 hover:text-accent hover:bg-background/10 inline-block px-6 py-1 border-r border-background/20 transition-colors"
> >
{article.title || 'No title'} {article.title || 'No title'}
@ -34,7 +35,8 @@ export function ArticleTicker() {
{articles.map((article, index) => ( {articles.map((article, index) => (
<Link <Link
key={`dup-${article.id}-${index}`} key={`dup-${article.id}-${index}`}
to={`/articles/${article.id}`} to="/articles/$id"
params={{ id: article.id }}
className="font-body text-sm uppercase tracking-wider text-background/80 hover:text-accent hover:bg-background/10 inline-block px-6 py-1 border-r border-background/20 transition-colors" className="font-body text-sm uppercase tracking-wider text-background/80 hover:text-accent hover:bg-background/10 inline-block px-6 py-1 border-r border-background/20 transition-colors"
> >
{article.title || 'No title'} {article.title || 'No title'}

View File

@ -122,7 +122,7 @@ export function HeroArticle() {
)} )}
<div className="flex items-center justify-between pt-4 border-t-2 border-foreground/10"> <div className="flex items-center justify-between pt-4 border-t-2 border-foreground/10">
<Link to={`/articles/${article.id}`}> <Link to="/articles/$id" params={{ id: article.id }}>
<Button variant="brutalAccent" className="gap-2"> <Button variant="brutalAccent" className="gap-2">
Read Full Story Read Full Story
<ArrowRight className="w-4 h-4" /> <ArrowRight className="w-4 h-4" />

View File

@ -65,7 +65,8 @@ export function LatestArticlesGrid() {
className={`group border-brutal-sm bg-card hover:shadow-brutal transition-all duration-150 hover:-translate-y-1 animate-fade-in-up stagger-${Math.min(index + 1, 12)}`} className={`group border-brutal-sm bg-card hover:shadow-brutal transition-all duration-150 hover:-translate-y-1 animate-fade-in-up stagger-${Math.min(index + 1, 12)}`}
> >
<Link <Link
to={`/articles/${article.id}`} to="/articles/$id"
params={{ id: article.id }}
className="block" className="block"
> >
{article.featuredImage ? ( {article.featuredImage ? (
@ -107,12 +108,12 @@ export function LatestArticlesGrid() {
</span> </span>
{article.category && ( {article.category && (
<Link <a
to={`/${article.category.slug}`} href={`/${article.category.slug}`}
className="px-2 py-0.5 border border-foreground bg-background text-foreground text-[10px] hover:bg-accent hover:border-accent transition-colors" className="px-2 py-0.5 border border-foreground bg-background text-foreground text-[10px] hover:bg-accent hover:border-accent transition-colors"
> >
{article.category.name} {article.category.name}
</Link> </a>
)} )}
</div> </div>
@ -121,7 +122,7 @@ export function LatestArticlesGrid() {
articleId={article.id} articleId={article.id}
title={article.title} title={article.title}
url={`${window.location.origin}/articles/${article.id}`} url={`${window.location.origin}/articles/${article.id}`}
excerpt={article.excerpt} excerpt={article.excerpt ?? undefined}
image={article.featuredImage} image={article.featuredImage}
tags={article.tags} tags={article.tags}
variant="compact" variant="compact"

View File

@ -39,7 +39,8 @@ export function ArchiveComponent() {
className="p-6 rounded-xl border bg-card hover:shadow-lg transition-shadow" className="p-6 rounded-xl border bg-card hover:shadow-lg transition-shadow"
> >
<Link <Link
to={`/articles/${article.id}`} to="/articles/$id"
params={{ id: article.id }}
className="block mb-4" className="block mb-4"
> >
<h2 className="text-xl font-semibold mb-2 line-clamp-2"> <h2 className="text-xl font-semibold mb-2 line-clamp-2">
@ -69,7 +70,7 @@ export function ArchiveComponent() {
articleId={article.id} articleId={article.id}
title={article.title} title={article.title}
url={`${window.location.origin}/articles/${article.id}`} url={`${window.location.origin}/articles/${article.id}`}
excerpt={article.excerpt} excerpt={article.excerpt ?? undefined}
image={article.featuredImage} image={article.featuredImage}
tags={article.tags} tags={article.tags}
variant="compact" variant="compact"

View File

@ -42,7 +42,7 @@ export function ArticleDetailComponent({ id }: { id: string }) {
return ( return (
<article className="max-w-3xl mx-auto"> <article className="max-w-3xl mx-auto">
<Link <Link
to="/articles" to="/archive"
className="inline-flex items-center gap-2 text-muted-foreground hover:text-foreground mb-8" className="inline-flex items-center gap-2 text-muted-foreground hover:text-foreground mb-8"
> >
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
@ -78,7 +78,7 @@ export function ArticleDetailComponent({ id }: { id: string }) {
articleId={data.id} articleId={data.id}
title={data.title} title={data.title}
url={typeof window !== 'undefined' ? window.location.href : ''} url={typeof window !== 'undefined' ? window.location.href : ''}
excerpt={data.excerpt} excerpt={data.excerpt ?? undefined}
image={data.featuredImage} image={data.featuredImage}
tags={data.tags} tags={data.tags}
/> />
@ -198,7 +198,7 @@ export function ArticleDetailComponent({ id }: { id: string }) {
articleId={data.id} articleId={data.id}
title={data.title} title={data.title}
url={typeof window !== 'undefined' ? window.location.href : ''} url={typeof window !== 'undefined' ? window.location.href : ''}
excerpt={data.excerpt} excerpt={data.excerpt ?? undefined}
image={data.featuredImage} image={data.featuredImage}
tags={data.tags} tags={data.tags}
variant="footer" variant="footer"

View File

@ -57,7 +57,7 @@ export function CategoryPage({ categorySlug, categoryName, categoryDescription }
{/* Hero Article - 2/3 width */} {/* Hero Article - 2/3 width */}
<div className="lg:col-span-2"> <div className="lg:col-span-2">
<div className="rounded-xl border bg-card overflow-hidden group hover:shadow-lg transition-shadow"> <div className="rounded-xl border bg-card overflow-hidden group hover:shadow-lg transition-shadow">
<Link to={`/articles/${heroArticle.id}`} className="block"> <Link to="/articles/$id" params={{ id: heroArticle.id }} className="block">
{heroArticle.featuredImage ? ( {heroArticle.featuredImage ? (
<div className="relative h-64 md:h-80 overflow-hidden"> <div className="relative h-64 md:h-80 overflow-hidden">
<img <img
@ -80,7 +80,7 @@ export function CategoryPage({ categorySlug, categoryName, categoryDescription }
</Link> </Link>
<div className="p-6"> <div className="p-6">
<Link to={`/articles/${heroArticle.id}`} className="block"> <Link to="/articles/$id" params={{ id: heroArticle.id }} className="block">
<h2 className="text-2xl font-bold mb-3 group-hover:text-primary transition-colors"> <h2 className="text-2xl font-bold mb-3 group-hover:text-primary transition-colors">
{heroArticle.title} {heroArticle.title}
</h2> </h2>
@ -108,7 +108,7 @@ export function CategoryPage({ categorySlug, categoryName, categoryDescription }
articleId={heroArticle.id} articleId={heroArticle.id}
title={heroArticle.title} title={heroArticle.title}
url={`${window.location.origin}/articles/${heroArticle.id}`} url={`${window.location.origin}/articles/${heroArticle.id}`}
excerpt={heroArticle.excerpt} excerpt={heroArticle.excerpt ?? undefined}
image={heroArticle.featuredImage} image={heroArticle.featuredImage}
tags={heroArticle.tags} tags={heroArticle.tags}
variant="compact" variant="compact"
@ -135,7 +135,8 @@ export function CategoryPage({ categorySlug, categoryName, categoryDescription }
className="p-6 rounded-xl border bg-card hover:shadow-lg transition-shadow group" className="p-6 rounded-xl border bg-card hover:shadow-lg transition-shadow group"
> >
<Link <Link
to={`/articles/${article.id}`} to="/articles/$id"
params={{ id: article.id }}
className="block mb-4" className="block mb-4"
> >
<h2 className="text-xl font-semibold mb-2 line-clamp-2 group-hover:text-primary transition-colors"> <h2 className="text-xl font-semibold mb-2 line-clamp-2 group-hover:text-primary transition-colors">
@ -165,7 +166,7 @@ export function CategoryPage({ categorySlug, categoryName, categoryDescription }
articleId={article.id} articleId={article.id}
title={article.title} title={article.title}
url={`${window.location.origin}/articles/${article.id}`} url={`${window.location.origin}/articles/${article.id}`}
excerpt={article.excerpt} excerpt={article.excerpt ?? undefined}
image={article.featuredImage} image={article.featuredImage}
tags={article.tags} tags={article.tags}
variant="compact" variant="compact"

View File

@ -25,7 +25,8 @@ export function ArticleTicker() {
{articles.map((article, index) => ( {articles.map((article, index) => (
<Link <Link
key={`${article.id}-${index}`} key={`${article.id}-${index}`}
to={`/articles/${article.id}`} to="/articles/$id"
params={{ id: article.id }}
className="font-body text-sm uppercase tracking-wider text-background/80 hover:text-accent hover:bg-background/10 inline-block px-6 py-1 border-r border-background/20 transition-colors" className="font-body text-sm uppercase tracking-wider text-background/80 hover:text-accent hover:bg-background/10 inline-block px-6 py-1 border-r border-background/20 transition-colors"
> >
{article.title || 'No title'} {article.title || 'No title'}
@ -34,7 +35,8 @@ export function ArticleTicker() {
{articles.map((article, index) => ( {articles.map((article, index) => (
<Link <Link
key={`dup-${article.id}-${index}`} key={`dup-${article.id}-${index}`}
to={`/articles/${article.id}`} to="/articles/$id"
params={{ id: article.id }}
className="font-body text-sm uppercase tracking-wider text-background/80 hover:text-accent hover:bg-background/10 inline-block px-6 py-1 border-r border-background/20 transition-colors" className="font-body text-sm uppercase tracking-wider text-background/80 hover:text-accent hover:bg-background/10 inline-block px-6 py-1 border-r border-background/20 transition-colors"
> >
{article.title || 'No title'} {article.title || 'No title'}

View File

@ -122,7 +122,7 @@ export function HeroArticle() {
)} )}
<div className="flex items-center justify-between pt-4 border-t-2 border-foreground/10"> <div className="flex items-center justify-between pt-4 border-t-2 border-foreground/10">
<Link to={`/articles/${article.id}`}> <Link to="/articles/$id" params={{ id: article.id }}>
<Button variant="brutalAccent" className="gap-2"> <Button variant="brutalAccent" className="gap-2">
Read Full Story Read Full Story
<ArrowRight className="w-4 h-4" /> <ArrowRight className="w-4 h-4" />

View File

@ -65,7 +65,8 @@ export function LatestArticlesGrid() {
className={`group border-brutal-sm bg-card hover:shadow-brutal transition-all duration-150 hover:-translate-y-1 animate-fade-in-up stagger-${Math.min(index + 1, 12)}`} className={`group border-brutal-sm bg-card hover:shadow-brutal transition-all duration-150 hover:-translate-y-1 animate-fade-in-up stagger-${Math.min(index + 1, 12)}`}
> >
<Link <Link
to={`/articles/${article.id}`} to="/articles/$id"
params={{ id: article.id }}
className="block" className="block"
> >
{article.featuredImage ? ( {article.featuredImage ? (
@ -107,12 +108,12 @@ export function LatestArticlesGrid() {
</span> </span>
{article.category && ( {article.category && (
<Link <a
to={`/${article.category.slug}`} href={`/${article.category.slug}`}
className="px-2 py-0.5 border border-foreground bg-background text-foreground text-[10px] hover:bg-accent hover:border-accent transition-colors" className="px-2 py-0.5 border border-foreground bg-background text-foreground text-[10px] hover:bg-accent hover:border-accent transition-colors"
> >
{article.category.name} {article.category.name}
</Link> </a>
)} )}
</div> </div>
@ -121,7 +122,7 @@ export function LatestArticlesGrid() {
articleId={article.id} articleId={article.id}
title={article.title} title={article.title}
url={`${window.location.origin}/articles/${article.id}`} url={`${window.location.origin}/articles/${article.id}`}
excerpt={article.excerpt} excerpt={article.excerpt ?? undefined}
image={article.featuredImage} image={article.featuredImage}
tags={article.tags} tags={article.tags}
variant="compact" variant="compact"

View File

@ -39,7 +39,8 @@ export function ArchiveComponent() {
className="p-6 rounded-xl border bg-card hover:shadow-lg transition-shadow" className="p-6 rounded-xl border bg-card hover:shadow-lg transition-shadow"
> >
<Link <Link
to={`/articles/${article.id}`} to="/articles/$id"
params={{ id: article.id }}
className="block mb-4" className="block mb-4"
> >
<h2 className="text-xl font-semibold mb-2 line-clamp-2"> <h2 className="text-xl font-semibold mb-2 line-clamp-2">
@ -69,7 +70,7 @@ export function ArchiveComponent() {
articleId={article.id} articleId={article.id}
title={article.title} title={article.title}
url={`${window.location.origin}/articles/${article.id}`} url={`${window.location.origin}/articles/${article.id}`}
excerpt={article.excerpt} excerpt={article.excerpt ?? undefined}
image={article.featuredImage} image={article.featuredImage}
tags={article.tags} tags={article.tags}
variant="compact" variant="compact"

View File

@ -42,7 +42,7 @@ export function ArticleDetailComponent({ id }: { id: string }) {
return ( return (
<article className="max-w-3xl mx-auto"> <article className="max-w-3xl mx-auto">
<Link <Link
to="/articles" to="/archive"
className="inline-flex items-center gap-2 text-muted-foreground hover:text-foreground mb-8" className="inline-flex items-center gap-2 text-muted-foreground hover:text-foreground mb-8"
> >
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
@ -78,7 +78,7 @@ export function ArticleDetailComponent({ id }: { id: string }) {
articleId={data.id} articleId={data.id}
title={data.title} title={data.title}
url={typeof window !== 'undefined' ? window.location.href : ''} url={typeof window !== 'undefined' ? window.location.href : ''}
excerpt={data.excerpt} excerpt={data.excerpt ?? undefined}
image={data.featuredImage} image={data.featuredImage}
tags={data.tags} tags={data.tags}
/> />
@ -198,7 +198,7 @@ export function ArticleDetailComponent({ id }: { id: string }) {
articleId={data.id} articleId={data.id}
title={data.title} title={data.title}
url={typeof window !== 'undefined' ? window.location.href : ''} url={typeof window !== 'undefined' ? window.location.href : ''}
excerpt={data.excerpt} excerpt={data.excerpt ?? undefined}
image={data.featuredImage} image={data.featuredImage}
tags={data.tags} tags={data.tags}
variant="footer" variant="footer"

View File

@ -57,7 +57,7 @@ export function CategoryPage({ categorySlug, categoryName, categoryDescription }
{/* Hero Article - 2/3 width */} {/* Hero Article - 2/3 width */}
<div className="lg:col-span-2"> <div className="lg:col-span-2">
<div className="rounded-xl border bg-card overflow-hidden group hover:shadow-lg transition-shadow"> <div className="rounded-xl border bg-card overflow-hidden group hover:shadow-lg transition-shadow">
<Link to={`/articles/${heroArticle.id}`} className="block"> <Link to="/articles/$id" params={{ id: heroArticle.id }} className="block">
{heroArticle.featuredImage ? ( {heroArticle.featuredImage ? (
<div className="relative h-64 md:h-80 overflow-hidden"> <div className="relative h-64 md:h-80 overflow-hidden">
<img <img
@ -80,7 +80,7 @@ export function CategoryPage({ categorySlug, categoryName, categoryDescription }
</Link> </Link>
<div className="p-6"> <div className="p-6">
<Link to={`/articles/${heroArticle.id}`} className="block"> <Link to="/articles/$id" params={{ id: heroArticle.id }} className="block">
<h2 className="text-2xl font-bold mb-3 group-hover:text-primary transition-colors"> <h2 className="text-2xl font-bold mb-3 group-hover:text-primary transition-colors">
{heroArticle.title} {heroArticle.title}
</h2> </h2>
@ -108,7 +108,7 @@ export function CategoryPage({ categorySlug, categoryName, categoryDescription }
articleId={heroArticle.id} articleId={heroArticle.id}
title={heroArticle.title} title={heroArticle.title}
url={`${window.location.origin}/articles/${heroArticle.id}`} url={`${window.location.origin}/articles/${heroArticle.id}`}
excerpt={heroArticle.excerpt} excerpt={heroArticle.excerpt ?? undefined}
image={heroArticle.featuredImage} image={heroArticle.featuredImage}
tags={heroArticle.tags} tags={heroArticle.tags}
variant="compact" variant="compact"
@ -135,7 +135,8 @@ export function CategoryPage({ categorySlug, categoryName, categoryDescription }
className="p-6 rounded-xl border bg-card hover:shadow-lg transition-shadow group" className="p-6 rounded-xl border bg-card hover:shadow-lg transition-shadow group"
> >
<Link <Link
to={`/articles/${article.id}`} to="/articles/$id"
params={{ id: article.id }}
className="block mb-4" className="block mb-4"
> >
<h2 className="text-xl font-semibold mb-2 line-clamp-2 group-hover:text-primary transition-colors"> <h2 className="text-xl font-semibold mb-2 line-clamp-2 group-hover:text-primary transition-colors">
@ -165,7 +166,7 @@ export function CategoryPage({ categorySlug, categoryName, categoryDescription }
articleId={article.id} articleId={article.id}
title={article.title} title={article.title}
url={`${window.location.origin}/articles/${article.id}`} url={`${window.location.origin}/articles/${article.id}`}
excerpt={article.excerpt} excerpt={article.excerpt ?? undefined}
image={article.featuredImage} image={article.featuredImage}
tags={article.tags} tags={article.tags}
variant="compact" variant="compact"

View File

@ -18,8 +18,8 @@ function checkPushSupport(): boolean {
); );
} }
function getInitialPermission(): NotificationPermission | 'not-supported' { function getInitialPermission(): NotificationPermission {
if (!checkPushSupport()) return 'not-supported'; if (!checkPushSupport()) return 'denied';
return Notification.permission; return Notification.permission;
} }
@ -27,7 +27,7 @@ export interface UsePushNotificationsReturn {
isSupported: boolean; isSupported: boolean;
isSubscribed: boolean; isSubscribed: boolean;
isLoading: boolean; isLoading: boolean;
permissionState: NotificationPermission | 'not-supported'; permissionState: NotificationPermission;
subscribe: () => Promise<boolean>; subscribe: () => Promise<boolean>;
unsubscribe: () => Promise<boolean>; unsubscribe: () => Promise<boolean>;
requestPermission: () => Promise<NotificationPermission>; requestPermission: () => Promise<NotificationPermission>;
@ -54,7 +54,7 @@ export function usePushNotifications(): UsePushNotificationsReturn {
const requestPermission = const requestPermission =
useCallback(async (): Promise<NotificationPermission> => { useCallback(async (): Promise<NotificationPermission> => {
if (!isSupported) return 'not-supported'; if (!isSupported) return 'denied';
const permission = await Notification.requestPermission(); const permission = await Notification.requestPermission();
setPermissionState(permission); setPermissionState(permission);
@ -96,9 +96,10 @@ export function usePushNotifications(): UsePushNotificationsReturn {
let subscription = await registration.pushManager.getSubscription(); let subscription = await registration.pushManager.getSubscription();
if (!subscription) { if (!subscription) {
const keyArray = urlBase64ToUint8Array(publicKey);
subscription = await registration.pushManager.subscribe({ subscription = await registration.pushManager.subscribe({
userVisibleOnly: true, userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(publicKey), applicationServerKey: keyArray.buffer as ArrayBuffer,
}); });
} }