💄 Optimize post detail view
This commit is contained in:
@@ -1,15 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-chip-group class="d-flex flex-wrap gap-2">
|
<div class="d-flex flex-wrap gap-2">
|
||||||
<!-- Add Reaction Button -->
|
<!-- Add Reaction Button -->
|
||||||
<v-chip
|
<v-chip
|
||||||
v-if="canReact"
|
v-if="canReact"
|
||||||
color="primary"
|
|
||||||
rounded
|
rounded
|
||||||
:disabled="submitting"
|
:disabled="submitting"
|
||||||
|
prepend-icon="mdi-plus"
|
||||||
@click="showReactionDialog"
|
@click="showReactionDialog"
|
||||||
>
|
>
|
||||||
<v-icon start size="16">mdi-plus</v-icon>
|
React
|
||||||
<span class="text-xs">React</span>
|
|
||||||
</v-chip>
|
</v-chip>
|
||||||
|
|
||||||
<!-- Existing Reactions -->
|
<!-- Existing Reactions -->
|
||||||
@@ -27,7 +26,7 @@
|
|||||||
{{ count }}
|
{{ count }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</v-chip-group>
|
</div>
|
||||||
|
|
||||||
<!-- Reaction Selection Dialog -->
|
<!-- Reaction Selection Dialog -->
|
||||||
<v-dialog v-model="reactionDialog" max-width="500" height="600">
|
<v-dialog v-model="reactionDialog" max-width="500" height="600">
|
||||||
@@ -258,15 +257,6 @@ function getReactionCount(symbol: string): number {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.post-reaction-list {
|
|
||||||
min-height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reaction-chip {
|
|
||||||
height: 28px !important;
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reaction-emoji {
|
.reaction-emoji {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
@@ -278,24 +268,10 @@ function getReactionCount(symbol: string): number {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.reaction-count {
|
.reaction-count {
|
||||||
height: 16px !important;
|
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dialog Styles */
|
|
||||||
.reaction-dialog {
|
|
||||||
height: 600px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-content {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
max-height: calc(600px - 80px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.reaction-section {
|
.reaction-section {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,18 +4,19 @@
|
|||||||
<v-progress-circular indeterminate size="64" color="primary" />
|
<v-progress-circular indeterminate size="64" color="primary" />
|
||||||
<p class="mt-4">Loading post...</p>
|
<p class="mt-4">Loading post...</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="error" class="text-center py-12">
|
<div v-else-if="error" class="text-center py-12">
|
||||||
<v-alert type="error" class="mb-4" prominent>
|
<v-alert type="error" class="mb-4" prominent>
|
||||||
<v-alert-title>Error Loading Post</v-alert-title>
|
<v-alert-title>Error Loading Post</v-alert-title>
|
||||||
{{ error?.statusMessage || "Failed to load post" }}
|
{{ error?.statusMessage || "Failed to load post" }}
|
||||||
</v-alert>
|
</v-alert>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="post" class="max-w-4xl mx-auto">
|
|
||||||
<!-- Article Type: Split Header and Content -->
|
<div v-else-if="post" class="max-w-7xl mx-auto">
|
||||||
<template v-if="post.type === 1">
|
<div class="grid grid-cols-1 lg:grid-cols-12 gap-4">
|
||||||
<!-- Post Header Section (Article) -->
|
<!-- Main Content Column -->
|
||||||
<v-card class="mb-4 elevation-2" rounded="lg">
|
<div class="lg:col-span-8 flex flex-col gap-4">
|
||||||
<v-card-text class="pa-6">
|
<v-card class="pa-6">
|
||||||
<post-header :item="post" class="mb-4" />
|
<post-header :item="post" class="mb-4" />
|
||||||
|
|
||||||
<!-- Post Title and Description -->
|
<!-- Post Title and Description -->
|
||||||
@@ -47,25 +48,17 @@
|
|||||||
<v-icon size="16">mdi-pencil</v-icon>
|
<v-icon size="16">mdi-pencil</v-icon>
|
||||||
<span>Updated {{ formatDate(post.updatedAt) }}</span>
|
<span>Updated {{ formatDate(post.updatedAt) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="flex items-center gap-1">
|
||||||
v-if="(post as any).viewCount || (post as any).view_count"
|
|
||||||
class="flex items-center gap-1"
|
|
||||||
>
|
|
||||||
<v-icon size="16">mdi-eye</v-icon>
|
<v-icon size="16">mdi-eye</v-icon>
|
||||||
<span
|
<span>
|
||||||
>{{
|
{{ post.viewsTotal }} / {{ post.viewsUnique }}
|
||||||
(post as any).viewCount || (post as any).view_count || 0
|
views
|
||||||
}}
|
</span>
|
||||||
views</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</v-card-text>
|
</v-card>
|
||||||
</v-card>
|
|
||||||
|
|
||||||
<!-- Merged Content and Attachments Section (Article) -->
|
<v-card class="pa-6">
|
||||||
<v-card class="mb-4 elevation-1" rounded="lg">
|
|
||||||
<v-card-text class="pa-8">
|
|
||||||
<article
|
<article
|
||||||
v-if="htmlContent"
|
v-if="htmlContent"
|
||||||
class="prose prose-xl dark:prose-invert prose-slate max-w-none mb-8"
|
class="prose prose-xl dark:prose-invert prose-slate max-w-none mb-8"
|
||||||
@@ -75,112 +68,58 @@
|
|||||||
|
|
||||||
<!-- Attachments within Content Section -->
|
<!-- Attachments within Content Section -->
|
||||||
<attachment-list :attachments="post.attachments || []" />
|
<attachment-list :attachments="post.attachments || []" />
|
||||||
</v-card-text>
|
</v-card>
|
||||||
</v-card>
|
</div>
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- Other Types: Merged Header, Content, and Attachments -->
|
<!-- Sidebar Column -->
|
||||||
<template v-else>
|
<div class="lg:col-span-4 flex flex-col gap-4">
|
||||||
<!-- Merged Header, Content, and Attachments Section -->
|
<!-- Tags Section -->
|
||||||
<v-card class="px-4 py-3 mb-4 elevation-1" rounded="lg">
|
<v-card
|
||||||
<v-card-text class="pa-6">
|
v-if="post.tags && post.tags.length > 0"
|
||||||
<post-header :item="post" class="mb-4" />
|
rounded="lg"
|
||||||
|
prepend-icon="mdi-tag-multiple"
|
||||||
<!-- Post Title and Description -->
|
title="Tags & Categories"
|
||||||
<div v-if="post.title || post.description" class="mb-4">
|
>
|
||||||
<h1
|
<v-card-text>
|
||||||
v-if="post.title"
|
<div class="flex flex-wrap gap-2">
|
||||||
class="text-3xl font-bold mb-3 leading-tight"
|
<v-chip
|
||||||
>
|
v-for="category in post.categories"
|
||||||
{{ post.title }}
|
:key="category.id"
|
||||||
</h1>
|
prepend-icon="mdi-tshape"
|
||||||
<p
|
rounded
|
||||||
v-if="post.description"
|
|
||||||
class="text-lg text-medium-emphasis leading-relaxed"
|
|
||||||
>
|
|
||||||
{{ post.description }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Post Metadata -->
|
|
||||||
<div
|
|
||||||
class="flex items-center gap-4 text-sm text-medium-emphasis mb-4"
|
|
||||||
>
|
|
||||||
<div class="flex items-center gap-1">
|
|
||||||
<v-icon size="16">mdi-calendar</v-icon>
|
|
||||||
<span>{{ formatDate(post.createdAt) }}</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="post.updatedAt && post.updatedAt !== post.createdAt"
|
|
||||||
class="flex items-center gap-1"
|
|
||||||
>
|
|
||||||
<v-icon size="16">mdi-pencil</v-icon>
|
|
||||||
<span>Updated {{ formatDate(post.updatedAt) }}</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="(post as any).viewCount || (post as any).view_count"
|
|
||||||
class="flex items-center gap-1"
|
|
||||||
>
|
|
||||||
<v-icon size="16">mdi-eye</v-icon>
|
|
||||||
<span
|
|
||||||
>{{
|
|
||||||
(post as any).viewCount || (post as any).view_count || 0
|
|
||||||
}}
|
|
||||||
views</span
|
|
||||||
>
|
>
|
||||||
|
{{ category.slug }}
|
||||||
|
</v-chip>
|
||||||
|
<v-chip
|
||||||
|
v-for="tag in post.tags"
|
||||||
|
:key="tag.id"
|
||||||
|
prepend-icon="mdi-tag"
|
||||||
|
rounded
|
||||||
|
>
|
||||||
|
{{ tag.slug }}
|
||||||
|
</v-chip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Post Reactions -->
|
||||||
<article
|
<v-card
|
||||||
v-if="htmlContent"
|
class="elevation-1"
|
||||||
class="prose prose-xl dark:prose-invert prose-slate max-w-none mb-8"
|
rounded="lg"
|
||||||
>
|
title="Reactions"
|
||||||
<div v-html="htmlContent" />
|
prepend-icon="mdi-thumb-up"
|
||||||
</article>
|
>
|
||||||
|
<v-card-text>
|
||||||
<!-- Attachments within Merged Section -->
|
<post-reaction-list
|
||||||
<attachment-list :attachments="post.attachments || []" />
|
can-react
|
||||||
</v-card-text>
|
:parent-id="id"
|
||||||
</v-card>
|
:reactions="(post as any).reactions || {}"
|
||||||
</template>
|
:reactions-made="(post as any).reactionsMade || {}"
|
||||||
|
@react="handleReaction"
|
||||||
<!-- Tags Section -->
|
/>
|
||||||
<v-card
|
</v-card-text>
|
||||||
v-if="post.tags && post.tags.length > 0"
|
</v-card>
|
||||||
class="mb-4 elevation-1"
|
</div>
|
||||||
rounded="lg"
|
|
||||||
>
|
|
||||||
<v-card-title class="text-h6">
|
|
||||||
<v-icon class="mr-2">mdi-tag-multiple</v-icon>
|
|
||||||
Tags
|
|
||||||
</v-card-title>
|
|
||||||
<v-card-text>
|
|
||||||
<div class="flex flex-wrap gap-2">
|
|
||||||
<v-chip
|
|
||||||
v-for="tag in post.tags"
|
|
||||||
:key="tag"
|
|
||||||
size="small"
|
|
||||||
variant="outlined"
|
|
||||||
color="primary"
|
|
||||||
class="cursor-pointer hover:bg-primary hover:text-primary-foreground transition-colors"
|
|
||||||
>
|
|
||||||
<v-icon start size="16">mdi-tag</v-icon>
|
|
||||||
{{ tag }}
|
|
||||||
</v-chip>
|
|
||||||
</div>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
|
|
||||||
<!-- Post Reactions -->
|
|
||||||
<div>
|
|
||||||
<post-reaction-list
|
|
||||||
can-react
|
|
||||||
:parent-id="id"
|
|
||||||
:reactions="(post as any).reactions || {}"
|
|
||||||
:reactions-made="(post as any).reactionsMade || {}"
|
|
||||||
@react="handleReaction"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</v-container>
|
</v-container>
|
||||||
|
|||||||
@@ -73,11 +73,19 @@ export interface SnPost {
|
|||||||
publisherId: string;
|
publisherId: string;
|
||||||
publisher: SnPublisher;
|
publisher: SnPublisher;
|
||||||
awards: unknown | null;
|
awards: unknown | null;
|
||||||
tags: string[];
|
tags: SnPostCategory[];
|
||||||
categories: string[];
|
categories: SnPostCategory[];
|
||||||
isTruncated: boolean;
|
isTruncated: boolean;
|
||||||
resourceIdentifier: string;
|
resourceIdentifier: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
deletedAt: string | null;
|
deletedAt: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SnPostCategory {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
name?: string;
|
||||||
|
posts?: SnPost[];
|
||||||
|
usage?: number;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user