diff --git a/src/lib/components/BlogCard.svelte b/src/lib/components/BlogCard.svelte index dd02d40..aa704c9 100644 --- a/src/lib/components/BlogCard.svelte +++ b/src/lib/components/BlogCard.svelte @@ -10,7 +10,9 @@ import { BLOG_POST_FRESHNESS_MILLIS, blogPostTypeToIcon, - blogPostTypeToString + blogPostTypeToString, + EventStatus, + postEventStatus } from '$lib/util/Blogs'; import DateWidget from '$lib/components/DateWidget.svelte'; import Icon from '@iconify/svelte'; @@ -20,21 +22,26 @@ post, size = BlogCardSize.Both, fullHeight = false - }: { post: App.BlogPost; size: BlogCardSize; fullHeight: boolean } = $props(); + }: { post: App.BlogPost; size?: BlogCardSize; fullHeight?: boolean } = $props(); const type: App.BlogPostType = post.type ?? 'article'; let isPostNew = $state(false); let isPostUpdated = $state(false); let isPostFresh = $derived(isPostNew || isPostUpdated); - // TODO: rndtrash: события и их актуальность + let eventStatus: EventStatus | undefined = $state(undefined); + let isPostEventOfInterest = $derived( + type === 'event' && + (eventStatus === EventStatus.NotStarted || eventStatus === EventStatus.InProgress) + ); + let eventHasStarted = $derived(eventStatus === EventStatus.InProgress); onMount(() => { - // rndtrash: Выполняем проверки на клиенте, чтобы плашка не скомпилировалась и потом не потеряла актуальность const dateNow = new Date().valueOf(); isPostNew = dateNow - new Date(post.date!).valueOf() <= BLOG_POST_FRESHNESS_MILLIS; isPostUpdated = post.dateChanged != null && dateNow - new Date(post.dateChanged).valueOf() <= BLOG_POST_FRESHNESS_MILLIS; + eventStatus = postEventStatus(post); }); /** @@ -71,7 +78,15 @@ href="/blog/{post.slug}" class="blog-card {fullHeight ? 'min-h-full' : ''} - {isPostUpdated ? 'updated' : isPostNew ? 'new' : ''} + {isPostEventOfInterest + ? eventHasStarted + ? 'eventOngoing' + : 'eventPreStart' + : isPostUpdated + ? 'updated' + : isPostNew + ? 'new' + : ''} {shortClass('flex-col justify-baseline')} {fullClass('flex-row justify-stretch', 'sm:flex-row sm:justify-stretch')}" > @@ -87,7 +102,15 @@ alt={post.thumbnailAlt ?? 'Миниатюра поста'} /> {/if} - {#if isPostFresh} + {#if isPostEventOfInterest} +
+ {#if eventStatus === EventStatus.NotStarted} + СКОРО НАЧАЛО + {:else} + СОБЫТИЕ + {/if} +
+ {:else if isPostFresh}
{#if isPostUpdated} ОБНОВЛЕНО @@ -99,25 +122,40 @@
- - {#if post.dateChanged} + {#if isPostEventOfInterest} + + {:else} + + {#if post.dateChanged} + + {/if} +
+ + + {blogPostTypeToString(type)} + +
{/if} -
- - - {blogPostTypeToString(type)} - -

{post.title}

@@ -139,7 +177,7 @@ } &.updated { - box-shadow: 0 0 0 4px var(--color-purple-600); + box-shadow: 0 0 0 calc(var(--spacing) * 1) var(--color-purple-600); .toast { @apply bg-purple-600; @@ -147,13 +185,29 @@ } &.new { - box-shadow: 0 0 0 4px var(--color-amber-600); + box-shadow: 0 0 0 calc(var(--spacing) * 1) var(--color-amber-600); .toast { @apply bg-amber-600; } } + &.eventPreStart { + box-shadow: 0 0 0 calc(var(--spacing) * 1) var(--color-rose-600); + + .toast { + @apply bg-rose-600; + } + } + + &.eventOngoing { + box-shadow: 0 0 0 calc(var(--spacing) * 1) var(--color-teal-600); + + .toast { + @apply bg-teal-600; + } + } + img.thumbnail { @apply absolute h-full w-full object-cover transition-transform; diff --git a/src/lib/components/DateWidget.svelte b/src/lib/components/DateWidget.svelte index fd52c69..90065a3 100644 --- a/src/lib/components/DateWidget.svelte +++ b/src/lib/components/DateWidget.svelte @@ -10,7 +10,7 @@ class: className = '' }: { dateString?: string; - type?: 'published' | 'updated'; + type?: 'published' | 'updated' | 'eventStart' | 'eventFinish'; highlight?: boolean; showTime?: boolean; class?: string; @@ -18,7 +18,9 @@ const typeToIcon = { published: 'material-symbols:calendar-today', - updated: 'material-symbols:update' + updated: 'material-symbols:update', + eventStart: 'material-symbols:rocket-launch', + eventFinish: 'material-symbols:sports-score' }; const icon = type ? typeToIcon[type] : undefined; @@ -28,7 +30,12 @@
{#if icon} diff --git a/src/lib/util/Blogs.ts b/src/lib/util/Blogs.ts index e10d18d..223ca87 100644 --- a/src/lib/util/Blogs.ts +++ b/src/lib/util/Blogs.ts @@ -8,6 +8,11 @@ export enum EventStatus { IsOver } +export function postIsEventOfInterest(post: App.BlogPost): boolean { + const status = postEventStatus(post); + return status === EventStatus.NotStarted || status === EventStatus.InProgress; +} + export function postEventStatus(post: App.BlogPost): EventStatus { if (post.type !== 'event' || post.dateEventFrom === undefined || post.dateEventTo === undefined) { return EventStatus.NotEvent; @@ -26,17 +31,21 @@ export function postEventStatus(post: App.BlogPost): EventStatus { export type PostComparer = (a: App.BlogPost, b: App.BlogPost) => number; export const sortPostsByPostDate: PostComparer = (a, b) => new Date(b.date!).valueOf() - new Date(a.date!).valueOf(); - -function laterDate(a: string, b?: string): number { - const dateA = new Date(a).valueOf(); - if (!b) return dateA; - - const dateB = new Date(b).valueOf(); - return Math.max(dateA, dateB); -} - export const sortPostsByPostAndUpdateDate: PostComparer = (a, b) => laterDate(b.date!, b.dateChanged) - laterDate(a.date!, a.dateChanged); +function laterDate(a: string, ...dates: (string | undefined)[]): number { + const dateA = new Date(a).valueOf(); + if (dates.length <= 0) return dateA; + + let max = dateA; + for (const d of dates) { + if (!d) continue; + const date = new Date(d).valueOf(); + max = Math.max(max, date); + }; + return max; +} + export async function fetchPostsSorted(postComparer?: PostComparer) { const allPosts = await fetchPosts(); diff --git a/src/pages/index.md b/src/pages/index.md index e206d50..ae91af5 100644 --- a/src/pages/index.md +++ b/src/pages/index.md @@ -36,4 +36,7 @@ __Tea Sanctuary__ — это также и сообщество едином Общие вопросы можно задавать в [сообществе Tea Sanctuary](https://teasanctuary.ru/discord). Там же можете написать личное сообщение администраторам. +Есть и другие способы следить за нашими новостями — например, [канал в Telegram](https://t.me/tea_sanctuary), +с комментариями и отдельным чатом. + Наши соцсети и почту для более важных обращений можно найти на странице [Контакты](/contact). diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index e617887..f6024d4 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,11 +1,24 @@ @@ -88,9 +101,11 @@

ПОСЛЕДНИЕ ПОСТЫ

- {#each page.data.posts as post, i} + {#each posts as post, i}
- + {#key post} + + {/key}
{/each}
diff --git a/src/routes/+page.ts b/src/routes/+page.ts index e430cc1..a94c88b 100644 --- a/src/routes/+page.ts +++ b/src/routes/+page.ts @@ -1,6 +1,6 @@ import { fetchPostsSorted, sortPostsByPostAndUpdateDate } from "$src/lib/util/Blogs"; -const LATEST_POSTS_COUNT = 3; +const LATEST_POSTS_COUNT = 5; export async function load() { let md: any diff --git a/src/routes/blog/+page.server.ts b/src/routes/blog/+page.server.ts index c5653b5..916e748 100644 --- a/src/routes/blog/+page.server.ts +++ b/src/routes/blog/+page.server.ts @@ -1,4 +1,4 @@ -import { fetchPostsSorted } from "$src/lib/util/Blogs"; +import { fetchPostsSorted } from "$lib/util/Blogs"; export async function load() { return { title: "Блог", description: "Новости и заметки проектов Tea Sanctuary", posts: await fetchPostsSorted() }; diff --git a/src/routes/blog/+page.svelte b/src/routes/blog/+page.svelte index da243da..3eed89a 100644 --- a/src/routes/blog/+page.svelte +++ b/src/routes/blog/+page.svelte @@ -1,8 +1,10 @@
@@ -39,6 +54,20 @@ пропускать новые посты! +{#if !!eventPosts && eventPosts.length > 0} +
+

АКТУАЛЬНЫЕ СОБЫТИЯ

+ +
+ {#each eventPosts as post, i} +
+ +
+ {/each} +
+
+{/if} +
{#each groupedPosts.entries() as [monthYear, postsInMonthYear]}

{/each} -

\ No newline at end of file +