From 17db6d4f3eafcac08e5de333539aba9c5aba902a Mon Sep 17 00:00:00 2001 From: Ivan Kuzmenko <6745157+rndtrash@users.noreply.github.com> Date: Sun, 16 Nov 2025 10:19:41 +0300 Subject: [PATCH 1/4] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB?= =?UTF-8?q?=20=D1=83=D0=BF=D0=BE=D0=BC=D0=B8=D0=BD=D0=B0=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=20=D0=A2=D0=B5=D0=BB=D0=B5=D0=B3=D1=80=D0=B0=D0=BC=D0=B0=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B3=D0=BB=D0=B0=D0=B2=D0=BD=D1=83=D1=8E=20?= =?UTF-8?q?=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/index.md | 3 +++ 1 file changed, 3 insertions(+) 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). From 9b03d0c197e540e850059de538db00e6431a9c67 Mon Sep 17 00:00:00 2001 From: Ivan Kuzmenko <6745157+rndtrash@users.noreply.github.com> Date: Sun, 16 Nov 2025 10:55:18 +0300 Subject: [PATCH 2/4] =?UTF-8?q?=D0=9F=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6?= =?UTF-8?q?=D0=BA=D0=B0=20=D1=81=D0=BE=D0=B1=D1=8B=D1=82=D0=B8=D0=B9=20?= =?UTF-8?q?=D0=B2=20=D0=BA=D0=B0=D1=80=D1=82=D0=BE=D1=87=D0=BA=D0=B0=D1=85?= =?UTF-8?q?=20=D0=B1=D0=BB=D0=BE=D0=B3=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/BlogCard.svelte | 100 +++++++++++++++++++++------ src/lib/components/DateWidget.svelte | 13 +++- src/lib/util/Blogs.ts | 18 +++-- 3 files changed, 101 insertions(+), 30 deletions(-) diff --git a/src/lib/components/BlogCard.svelte b/src/lib/components/BlogCard.svelte index dd02d40..25bf97d 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'; @@ -26,15 +28,20 @@ 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..3b193dc 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; @@ -27,12 +32,17 @@ 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 { +function laterDate(a: string, ...dates: (string | undefined)[]): number { const dateA = new Date(a).valueOf(); - if (!b) return dateA; + if (dates.length <= 0) return dateA; - const dateB = new Date(b).valueOf(); - return Math.max(dateA, dateB); + 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 const sortPostsByPostAndUpdateDate: PostComparer = (a, b) => laterDate(b.date!, b.dateChanged) - laterDate(a.date!, a.dateChanged); From d6c3c4990cec2e4b8598d472ef8a2789f0d42e5c Mon Sep 17 00:00:00 2001 From: Ivan Kuzmenko <6745157+rndtrash@users.noreply.github.com> Date: Sun, 16 Nov 2025 10:55:58 +0300 Subject: [PATCH 3/4] =?UTF-8?q?=D0=A3=D0=B2=D0=B5=D0=BB=D0=B8=D1=87=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BA=D0=BE=D0=BB=D0=B8=D1=87=D0=B5=D1=81=D1=82=D0=B2?= =?UTF-8?q?=D0=BE=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=D0=B4=D0=BD=D0=B8=D1=85?= =?UTF-8?q?=20=D0=BF=D0=BE=D1=81=D1=82=D0=BE=D0=B2=20=D0=B4=D0=BE=205?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/+page.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 828cba41bd87a6535ee7c64ac7b98fb475a8dffb Mon Sep 17 00:00:00 2001 From: Ivan Kuzmenko <6745157+rndtrash@users.noreply.github.com> Date: Sun, 16 Nov 2025 11:31:13 +0300 Subject: [PATCH 4/4] =?UTF-8?q?=D0=90=D0=BA=D1=82=D1=83=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D1=81=D0=BE=D0=B1=D1=8B=D1=82=D0=B8=D1=8F?= =?UTF-8?q?=20=D0=B2=D1=8B=D1=81=D1=82=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B?= =?UTF-8?q?=20=D0=B2=D0=BF=D0=B5=D1=80=D1=91=D0=B4=20=D1=81=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/BlogCard.svelte | 2 +- src/lib/util/Blogs.ts | 3 +-- src/routes/+page.svelte | 23 +++++++++++++++---- src/routes/blog/+page.server.ts | 2 +- src/routes/blog/+page.svelte | 37 ++++++++++++++++++++++++++---- 5 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/lib/components/BlogCard.svelte b/src/lib/components/BlogCard.svelte index 25bf97d..aa704c9 100644 --- a/src/lib/components/BlogCard.svelte +++ b/src/lib/components/BlogCard.svelte @@ -22,7 +22,7 @@ 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); diff --git a/src/lib/util/Blogs.ts b/src/lib/util/Blogs.ts index 3b193dc..223ca87 100644 --- a/src/lib/util/Blogs.ts +++ b/src/lib/util/Blogs.ts @@ -31,6 +31,7 @@ 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(); +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(); @@ -45,8 +46,6 @@ function laterDate(a: string, ...dates: (string | undefined)[]): number { return max; } -export const sortPostsByPostAndUpdateDate: PostComparer = (a, b) => laterDate(b.date!, b.dateChanged) - laterDate(a.date!, a.dateChanged); - export async function fetchPostsSorted(postComparer?: PostComparer) { const allPosts = await fetchPosts(); 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/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 +