1
0
mirror of https://github.com/robonen/lorem-blog.git synced 2026-03-20 10:54:38 +00:00

feat(posts): add Post entity with types and UI components for content, meta, and title

This commit is contained in:
2025-06-15 15:39:15 +07:00
parent 268a6f6f42
commit ff91e96fc6
5 changed files with 81 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
export * from './types';
export { default as PostContent } from './ui/PostContent.vue';
export { default as PostMeta } from './ui/PostMeta.vue';
export { default as PostTitle } from './ui/PostTitle.vue';

View File

@@ -0,0 +1,9 @@
export interface Post {
id: number;
title: string;
content_short: string;
content_full: string;
created_at: string;
cover: string;
tags: string[];
}

View File

@@ -0,0 +1,5 @@
<template>
<p class="text-base">
<slot />
</p>
</template>

View File

@@ -0,0 +1,48 @@
<script lang="ts">
export interface PostMetaProps {
/**
* Post creation date in ISO format.
*/
createdAt: string;
/**
* Post content.
*/
content: string;
/**
* Post comments length.
*/
commentsLength: number;
}
</script>
<script setup lang="ts">
import { computed } from 'vue';
import { ChatIcon, ClockIcon } from '@/shared/icons';
import { calculateReadingTime, formatDate, pluralize } from '@/shared/utils';
const { createdAt, content, commentsLength } = defineProps<PostMetaProps>();
const readingTime = computed(() => calculateReadingTime(content));
const formattedDate = computed(() => formatDate(createdAt));
const formattedComments = computed(() => pluralize(commentsLength, ['комментарий', 'комментария', 'комментариев']));
</script>
<template>
<ul class="flex items-center gap-x-4 text-foreground-muted text-sm">
<li class="flex items-center gap-x-1" aria-label="Дата публикации">
{{ formattedDate }}
</li>
<span class="size-1 rounded-full bg-foreground-muted" aria-hidden="true" />
<li class="flex items-center gap-x-1" aria-label="Длительность чтения">
<ClockIcon class="size-5" />
{{ readingTime }} мин
</li>
<span class="size-1 rounded-full bg-foreground-muted" aria-hidden="true" />
<li class="flex items-center gap-x-1" aria-label="Количество комментариев">
<ChatIcon class="size-5" />
{{ commentsLength }} {{ formattedComments }}
</li>
</ul>
</template>

View File

@@ -0,0 +1,15 @@
<script lang="ts">
export interface PostTitleProps {
as?: keyof HTMLElementTagNameMap;
}
</script>
<script setup lang="ts">
const { as: tag = 'h1' } = defineProps<PostTitleProps>();
</script>
<template>
<component :is="tag" class="text-xl font-semibold">
<slot />
</component>
</template>