mirror of
https://github.com/robonen/lorem-blog.git
synced 2026-03-20 02:44:39 +00:00
feat(posts): add Post entity with types and UI components for content, meta, and title
This commit is contained in:
4
src/entities/Post/index.ts
Normal file
4
src/entities/Post/index.ts
Normal 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';
|
||||||
9
src/entities/Post/types.ts
Normal file
9
src/entities/Post/types.ts
Normal 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[];
|
||||||
|
}
|
||||||
5
src/entities/Post/ui/PostContent.vue
Normal file
5
src/entities/Post/ui/PostContent.vue
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<template>
|
||||||
|
<p class="text-base">
|
||||||
|
<slot />
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
48
src/entities/Post/ui/PostMeta.vue
Normal file
48
src/entities/Post/ui/PostMeta.vue
Normal 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>
|
||||||
15
src/entities/Post/ui/PostTitle.vue
Normal file
15
src/entities/Post/ui/PostTitle.vue
Normal 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>
|
||||||
Reference in New Issue
Block a user