Подсветка свежих или недавно обновлённых постов

This commit is contained in:
Иван Кузьменко 2025-09-30 07:11:32 +03:00
parent 3c55a37ed8
commit 2e99b04261
2 changed files with 59 additions and 15 deletions

View file

@ -7,13 +7,21 @@
</script> </script>
<script lang="ts"> <script lang="ts">
import Icon from '@iconify/svelte'; import { BLOG_POST_FRESHNESS_MILLIS } from '$lib/util/Blogs';
import DateWidget from '$lib/components/DateWidget.svelte';
export let post: App.BlogPost; export let post: App.BlogPost;
export let size: BlogCardSize = BlogCardSize.Both; export let size: BlogCardSize = BlogCardSize.Both;
const dateNow = new Date().valueOf();
const isPostNew = dateNow - new Date(post.date!).valueOf() <= BLOG_POST_FRESHNESS_MILLIS;
const isPostUpdated =
post.dateChanged != null &&
dateNow - new Date(post.dateChanged).valueOf() <= BLOG_POST_FRESHNESS_MILLIS;
const isPostFresh = isPostNew || isPostUpdated;
/** /**
* rndtrash: пришлось дублировать классы с модификатором и без, потому что Tailwind ОЧЕНЬ не любит, * rndtrash: пришлось дублировать классы с модификатором и без, потому что Tailwind просто не понимает,
* когда его классы склеивают из нескольких частей * когда его классы склеивают из нескольких частей
*/ */
@ -34,15 +42,18 @@
* *
* Возвращает пустую строку, если плашка может быть только полноразмерной * Возвращает пустую строку, если плашка может быть только полноразмерной
* @param classes * @param classes
* @param modClasses
*/ */
function shortClass(classes: string): string { function shortClass(classes: string, modClasses?: string): string {
return size === BlogCardSize.Long ? '' : classes; if (size === BlogCardSize.Long) return '';
return size === BlogCardSize.Both && modClasses ? modClasses : classes;
} }
</script> </script>
<a <a
href="/blog/{post.slug}" href="/blog/{post.slug}"
class="blog-card class="blog-card
{isPostUpdated ? 'updated' : isPostNew ? 'new' : ''}
{shortClass('flex-col justify-baseline')} {shortClass('flex-col justify-baseline')}
{fullClass('flex-row justify-stretch', 'sm:flex-row sm:justify-stretch')}" {fullClass('flex-row justify-stretch', 'sm:flex-row sm:justify-stretch')}"
> >
@ -58,19 +69,31 @@
alt={post.thumbnailAlt ?? 'Миниатюра поста'} alt={post.thumbnailAlt ?? 'Миниатюра поста'}
/> />
{/if} {/if}
{#if isPostFresh}
<div class="toast {fullClass('hidden', 'sm:hidden')}">
{#if isPostUpdated}
ОБНОВЛЕНО
{:else}
НОВОЕ
{/if}
</div>
{/if}
</div> </div>
<div class="flex w-full flex-col justify-center p-4 break-words md:p-8"> <div class="flex w-full flex-col justify-center p-4 break-words md:p-8">
<div class="flex flex-row flex-wrap justify-between gap-4 pb-4"> <div class="flex flex-row flex-wrap justify-start gap-4 pb-2">
<div class="flex items-center text-lg font-bold"> <DateWidget
<Icon icon="material-symbols:calendar-today" class="mr-3" width={24} height={24} /> class={post.dateChanged ? shortClass('hidden', 'not-sm:hidden') : ''}
<p> dateString={post.date}
{new Date(post.date!).toLocaleString('default', { type="published"
month: 'short', highlight={isPostNew && !isPostUpdated}
day: 'numeric', />
year: 'numeric' {#if post.dateChanged}
})} <DateWidget
</p> dateString={post.dateChanged}
</div> type="updated"
highlight={isPostUpdated}
/>
{/if}
</div> </div>
<h2 class="text-3xl font-bold">{post.title}</h2> <h2 class="text-3xl font-bold">{post.title}</h2>
@ -87,6 +110,26 @@
.blog-card { .blog-card {
@apply flex w-full max-w-5xl overflow-hidden rounded-lg bg-slate-100 text-slate-950 drop-shadow-xl transition-all hover:drop-shadow-2xl; @apply flex w-full max-w-5xl overflow-hidden rounded-lg bg-slate-100 text-slate-950 drop-shadow-xl transition-all hover:drop-shadow-2xl;
.toast {
@apply absolute top-0 right-0 rounded-bl-lg p-2 font-bold text-slate-50;
}
&.updated {
box-shadow: 0 0 0 4px var(--color-purple-600);
.toast {
@apply bg-purple-600;
}
}
&.new {
box-shadow: 0 0 0 4px var(--color-amber-600);
.toast {
@apply bg-amber-600;
}
}
img.thumbnail { img.thumbnail {
@apply absolute h-full w-full object-cover transition-transform; @apply absolute h-full w-full object-cover transition-transform;

View file

@ -1,6 +1,7 @@
import path from 'path'; import path from 'path';
export const THUMBNAIL_DEFAULT = "https://teasanctuary.ru/common/background-day.webp"; export const THUMBNAIL_DEFAULT = "https://teasanctuary.ru/common/background-day.webp";
export const BLOG_POST_FRESHNESS_MILLIS = 3 * 24 * 60 * 60 * 1000; // 3 дня
export type PostComparer = (a: App.BlogPost, b: App.BlogPost) => number; export type PostComparer = (a: App.BlogPost, b: App.BlogPost) => number;