Блоги #1

Merged
rndtrash merged 64 commits from feature-blogs into master 2025-10-22 08:44:56 +03:00
3 changed files with 103 additions and 40 deletions
Showing only changes of commit be6615ff48 - Show all commits

View file

@ -0,0 +1,100 @@
<script lang="ts" module>
export enum BlogCardSize {
Short,
Long,
Both
}
</script>
<script lang="ts">
import Icon from '@iconify/svelte';
export let post: App.BlogPost;
export let size: BlogCardSize = BlogCardSize.Both;
/**
* rndtrash: пришлось дублировать классы с модификатором и без, потому что Tailwind ОЧЕНЬ не любит,
* когда его классы склеивают из нескольких частей
*/
/**
* Возвращает список классов для полноразмерной плашки.
*
* Возвращает пустую строку, если плашка может быть только короткой
* @param classes
* @param modClasses
*/
function fullClass(classes: string, modClasses: string): string {
if (size === BlogCardSize.Short) return '';
return size === BlogCardSize.Both ? modClasses : classes;
}
/**
* Возвращает список классов для короткой карточки.
*
* Возвращает пустую строку, если плашка может быть только полноразмерной
* @param classes
*/
function shortClass(classes: string): string {
return size === BlogCardSize.Long ? '' : classes;
}
</script>
<a
href="/blog/{post.slug}"
class="blog-card
{shortClass('flex-col justify-baseline')}
{fullClass('flex-row justify-stretch', 'sm:flex-row sm:justify-stretch')}"
>
<div
class="relative w-full basis-auto overflow-hidden
{shortClass('h-32')}
{fullClass('h-auto basis-1/3', 'sm:h-auto sm:basis-1/3')}"
>
{#if post.thumbnail}
<img
class="thumbnail"
src={`/blog/${post.slug}/${post.thumbnail}`}
alt={post.thumbnailAlt ?? 'Миниатюра поста'}
/>
{/if}
</div>
<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 items-center text-lg font-bold">
<Icon icon="material-symbols:calendar-today" class="mr-3" width={24} height={24} />
<p>
{new Date(post.date!).toLocaleString('default', {
month: 'short',
day: 'numeric',
year: 'numeric'
})}
</p>
</div>
</div>
<h2 class="text-3xl font-bold">{post.title}</h2>
{#if post.description}
<p>{post.description}</p>
{/if}
</div>
</a>
<style>
@import '$src/app.css';
.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;
img.thumbnail {
@apply absolute h-full w-full object-cover transition-transform;
transform: scale(1);
}
&:hover img.thumbnail {
transform: scale(1.1);
}
}
</style>

View file

@ -1,8 +1,8 @@
<script lang="ts"> <script lang="ts">
import { page } from '$app/state'; import { page } from '$app/state';
import Icon from '@iconify/svelte';
import SocialHyperlink from '$src/lib/components/SocialHyperlink.svelte'; import SocialHyperlink from '$src/lib/components/SocialHyperlink.svelte';
import InfoBlock from '$src/lib/components/InfoBlock.svelte'; import InfoBlock from '$src/lib/components/InfoBlock.svelte';
import BlogCard from '$src/lib/components/BlogCard.svelte';
function groupPostsByMonthYear(posts: App.BlogPost[]) { function groupPostsByMonthYear(posts: App.BlogPost[]) {
const groupedPosts = new Map<string, App.BlogPost[]>(); const groupedPosts = new Map<string, App.BlogPost[]>();
@ -48,44 +48,7 @@
</h1> </h1>
<div class="flex flex-col flex-wrap items-center gap-4"> <div class="flex flex-col flex-wrap items-center gap-4">
{#each postsInMonthYear as post, i} {#each postsInMonthYear as post, i}
<a <BlogCard {post} />
href="/blog/{post.slug}"
class="flex w-full max-w-5xl flex-col justify-baseline overflow-hidden rounded-lg bg-slate-100 text-slate-950 drop-shadow-xl transition-all hover:drop-shadow-2xl sm:flex-row sm:justify-stretch"
>
<div class="relative h-32 w-full basis-auto sm:h-auto sm:basis-1/3">
{#if post.thumbnail}
<img
class="absolute h-full w-full object-cover"
src={`/blog/${post.slug}/${post.thumbnail}`}
alt={post.thumbnailAlt ?? 'Миниатюра поста'}
/>
{/if}
</div>
<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 items-center text-lg font-bold">
<Icon
icon="material-symbols:calendar-today"
class="mr-3"
style="transform: scale( 1.3 )"
/>
<p>
{new Date(post.date!).toLocaleString('default', {
month: 'short',
day: 'numeric',
year: 'numeric'
})}
</p>
</div>
</div>
<h2 class="text-3xl font-bold">{post.title}</h2>
{#if post.description}
<p>{post.description}</p>
{/if}
</div>
</a>
{/each} {/each}
</div> </div>
{/each} {/each}

View file

@ -38,7 +38,7 @@ const config = {
}, },
extensions: ['.svelte', '.md'], extensions: ['.svelte', '.md'],
preprocess: [ preprocess: [
vitePreprocess(), vitePreprocess({ script: true }),
mdsvex({ mdsvex({
extensions: ['.md'], extensions: ['.md'],
layout: join(__dirname, "./src/lib/components/MdsvexLayout.svelte") layout: join(__dirname, "./src/lib/components/MdsvexLayout.svelte")