Compare commits

..

No commits in common. "828cba41bd87a6535ee7c64ac7b98fb475a8dffb" and "e61e48fb51792ebccc0091d0b7888cd53796908d" have entirely different histories.

8 changed files with 43 additions and 160 deletions

View file

@ -10,9 +10,7 @@
import {
BLOG_POST_FRESHNESS_MILLIS,
blogPostTypeToIcon,
blogPostTypeToString,
EventStatus,
postEventStatus
blogPostTypeToString
} from '$lib/util/Blogs';
import DateWidget from '$lib/components/DateWidget.svelte';
import Icon from '@iconify/svelte';
@ -22,26 +20,21 @@
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);
let eventStatus: EventStatus | undefined = $state(undefined);
let isPostEventOfInterest = $derived(
type === 'event' &&
(eventStatus === EventStatus.NotStarted || eventStatus === EventStatus.InProgress)
);
let eventHasStarted = $derived(eventStatus === EventStatus.InProgress);
// TODO: rndtrash: события и их актуальность
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);
});
/**
@ -78,15 +71,7 @@
href="/blog/{post.slug}"
class="blog-card
{fullHeight ? 'min-h-full' : ''}
{isPostEventOfInterest
? eventHasStarted
? 'eventOngoing'
: 'eventPreStart'
: isPostUpdated
? 'updated'
: isPostNew
? 'new'
: ''}
{isPostUpdated ? 'updated' : isPostNew ? 'new' : ''}
{shortClass('flex-col justify-baseline')}
{fullClass('flex-row justify-stretch', 'sm:flex-row sm:justify-stretch')}"
>
@ -102,15 +87,7 @@
alt={post.thumbnailAlt ?? 'Миниатюра поста'}
/>
{/if}
{#if isPostEventOfInterest}
<div class="toast {fullClass('hidden', 'sm:hidden')}">
{#if eventStatus === EventStatus.NotStarted}
СКОРО НАЧАЛО
{:else}
СОБЫТИЕ
{/if}
</div>
{:else if isPostFresh}
{#if isPostFresh}
<div class="toast {fullClass('hidden', 'sm:hidden')}">
{#if isPostUpdated}
ОБНОВЛЕНО
@ -122,20 +99,6 @@
</div>
<div class="flex w-full flex-col justify-center p-4 break-words">
<div class="flex flex-row flex-wrap justify-start gap-4 pb-2">
{#if isPostEventOfInterest}
<DateWidget
class={eventHasStarted ? shortClass('hidden', 'not-sm:hidden') : ''}
dateString={post.dateEventFrom}
type="eventStart"
highlight={!eventHasStarted}
/>
<DateWidget
class={!eventHasStarted ? shortClass('hidden', 'not-sm:hidden') : ''}
dateString={post.dateEventTo}
type="eventFinish"
highlight={eventHasStarted}
/>
{:else}
<DateWidget
class={post.dateChanged ? shortClass('hidden', 'not-sm:hidden') : ''}
dateString={post.date}
@ -155,7 +118,6 @@
{blogPostTypeToString(type)}
</span>
</div>
{/if}
</div>
<h2 class="text-3xl font-bold">{post.title}</h2>
@ -177,7 +139,7 @@
}
&.updated {
box-shadow: 0 0 0 calc(var(--spacing) * 1) var(--color-purple-600);
box-shadow: 0 0 0 4px var(--color-purple-600);
.toast {
@apply bg-purple-600;
@ -185,29 +147,13 @@
}
&.new {
box-shadow: 0 0 0 calc(var(--spacing) * 1) var(--color-amber-600);
box-shadow: 0 0 0 4px 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;

View file

@ -10,7 +10,7 @@
class: className = ''
}: {
dateString?: string;
type?: 'published' | 'updated' | 'eventStart' | 'eventFinish';
type?: 'published' | 'updated';
highlight?: boolean;
showTime?: boolean;
class?: string;
@ -18,9 +18,7 @@
const typeToIcon = {
published: 'material-symbols:calendar-today',
updated: 'material-symbols:update',
eventStart: 'material-symbols:rocket-launch',
eventFinish: 'material-symbols:sports-score'
updated: 'material-symbols:update'
};
const icon = type ? typeToIcon[type] : undefined;
@ -30,12 +28,7 @@
<div
class="flex flex-nowrap items-center gap-2 p-1 text-lg font-bold {className} rounded-lg
{highlightClasses(
type === 'published' ? 'bg-amber-600' : type === 'updated' ? 'bg-purple-600' : ''
)}
{highlightClasses(
type === 'eventStart' ? 'bg-rose-600' : type === 'eventFinish' ? 'bg-teal-600' : ''
)}
{highlightClasses(type == 'published' ? 'bg-amber-600' : 'bg-purple-600')}
{highlightClasses('text-slate-50')}"
>
{#if icon}

View file

@ -8,11 +8,6 @@ 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;
@ -31,21 +26,17 @@ 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 {
function laterDate(a: string, b?: string): number {
const dateA = new Date(a).valueOf();
if (dates.length <= 0) return dateA;
if (!b) 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;
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);
export async function fetchPostsSorted(postComparer?: PostComparer) {
const allPosts = await fetchPosts();

View file

@ -36,7 +36,4 @@ __Tea Sanctuary__ &mdash; это также и сообщество едином
Общие вопросы можно задавать в [сообществе Tea Sanctuary](https://teasanctuary.ru/discord).
Там же можете написать личное сообщение администраторам.
Есть и другие способы следить за нашими новостями &mdash; например, [канал в Telegram](https://t.me/tea_sanctuary),
с комментариями и отдельным чатом.
Наши соцсети и почту для более важных обращений можно найти на странице [Контакты](/contact).

View file

@ -1,24 +1,11 @@
<script lang="ts">
import SocialButton from '$lib/components/SocialButton.svelte';
import { PUBLIC_TS_DISCORD, PUBLIC_TS_TELEGRAM } from '$env/static/public';
import BlogCard, { BlogCardSize } from '$lib/components/BlogCard.svelte';
import BlogCard, { BlogCardSize } from '$src/lib/components/BlogCard.svelte';
import { page } from '$app/state';
import type { PageData } from './$types';
import { onMount } from 'svelte';
import { postIsEventOfInterest } from '$lib/util/Blogs';
let { data }: { data: PageData } = $props();
// postIsEventOfInterest(b) ? b.dateEventTo : undefined
let posts: App.BlogPost[] = $state(page.data.posts);
onMount(() => {
const dateToNum = (d: string) => new Date(d).valueOf();
posts = posts.sort(
(a, b) =>
dateToNum(postIsEventOfInterest(b) ? b.dateEventTo! : b.date!) -
dateToNum(postIsEventOfInterest(a) ? a.dateEventTo! : a.date!)
);
});
export let data: PageData;
</script>
<svelte:head>
@ -101,11 +88,9 @@
<h1 class="font-disket text-center text-2xl font-bold sm:text-4xl">ПОСЛЕДНИЕ ПОСТЫ</h1>
<div class="flex flex-row items-stretch justify-evenly gap-4 overflow-x-auto p-4">
{#each posts as post, i}
{#each page.data.posts as post, i}
<div class="aspect-3/2 w-80 shrink-0">
{#key post}
<BlogCard {post} size={BlogCardSize.Short} fullHeight />
{/key}
</div>
{/each}
</div>

View file

@ -1,6 +1,6 @@
import { fetchPostsSorted, sortPostsByPostAndUpdateDate } from "$src/lib/util/Blogs";
const LATEST_POSTS_COUNT = 5;
const LATEST_POSTS_COUNT = 3;
export async function load() {
let md: any

View file

@ -1,4 +1,4 @@
import { fetchPostsSorted } from "$lib/util/Blogs";
import { fetchPostsSorted } from "$src/lib/util/Blogs";
export async function load() {
return { title: "Блог", description: "Новости и заметки проектов Tea Sanctuary", posts: await fetchPostsSorted() };

View file

@ -1,10 +1,8 @@
<script lang="ts">
import { page } from '$app/state';
import SocialHyperlink from '$lib/components/SocialHyperlink.svelte';
import InfoBlock from '$lib/components/InfoBlock.svelte';
import BlogCard, { BlogCardSize } from '$lib/components/BlogCard.svelte';
import { postIsEventOfInterest, type PostComparer } from '$lib/util/Blogs';
import { onMount } from 'svelte';
import SocialHyperlink from '$src/lib/components/SocialHyperlink.svelte';
import InfoBlock from '$src/lib/components/InfoBlock.svelte';
import BlogCard from '$src/lib/components/BlogCard.svelte';
function groupPostsByMonthYear(posts: App.BlogPost[]) {
const groupedPosts = new Map<string, App.BlogPost[]>();
@ -21,20 +19,7 @@
return groupedPosts;
}
function getEventsOfInterest(posts: App.BlogPost[]) {
// Сортировка в обратном порядке - чем ближе к завершению, тем раньше в списке
const sortPostsByEvent: PostComparer = (a, b) =>
new Date(a.dateEventTo!).valueOf() - new Date(b.dateEventTo!).valueOf();
return posts.filter((a) => postIsEventOfInterest(a)).sort(sortPostsByEvent);
}
const groupedPosts = groupPostsByMonthYear(page.data.posts);
let eventPosts: App.BlogPost[] = $state([]);
onMount(() => {
eventPosts = getEventsOfInterest(page.data.posts);
});
</script>
<section class="hero flex shrink-0 flex-col items-center justify-center gap-5 overflow-hidden p-4">
@ -54,20 +39,6 @@
пропускать новые посты!
</InfoBlock>
{#if !!eventPosts && eventPosts.length > 0}
<section class="flex flex-col items-stretch bg-amber-50 pt-4">
<h1 class="font-disket text-center text-2xl font-bold sm:text-4xl">АКТУАЛЬНЫЕ СОБЫТИЯ</h1>
<div class="flex flex-row items-stretch justify-evenly gap-4 overflow-x-auto p-4">
{#each eventPosts as post, i}
<div class="aspect-3/2 w-80 shrink-0">
<BlogCard {post} size={BlogCardSize.Short} fullHeight />
</div>
{/each}
</div>
</section>
{/if}
<section class="flex flex-col items-stretch p-2 pb-8 md:p-4">
{#each groupedPosts.entries() as [monthYear, postsInMonthYear]}
<h1