Compare commits
2
Commits
1db1698174
...
a74299d716
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a74299d716 | ||
|
|
da0333e09c |
@@ -995,7 +995,12 @@ func (s *Store) Create(in model.PostInput) (model.Post, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.ID = id
|
p.ID = id
|
||||||
if err := s.setTags(id, in.Tags); err != nil {
|
// 标签是长文的组织方式;短文(类推微博)一律不打标签
|
||||||
|
tags := in.Tags
|
||||||
|
if p.Kind == model.KindShort {
|
||||||
|
tags = nil
|
||||||
|
}
|
||||||
|
if err := s.setTags(id, tags); err != nil {
|
||||||
return p, err
|
return p, err
|
||||||
}
|
}
|
||||||
return s.Get(id)
|
return s.Get(id)
|
||||||
@@ -1054,8 +1059,13 @@ func (s *Store) Update(id int64, in model.PostInput) (model.Post, error) {
|
|||||||
p.PublishedAt, p.UpdatedAt, p.ReadingMinutes, encodeImages(p.Images), encodeLinkCard(p.LinkCard), id); err != nil {
|
p.PublishedAt, p.UpdatedAt, p.ReadingMinutes, encodeImages(p.Images), encodeLinkCard(p.LinkCard), id); err != nil {
|
||||||
return p, err
|
return p, err
|
||||||
}
|
}
|
||||||
if in.Tags != nil {
|
// 短文一律无标签:切换类型或直接保存时都把旧标签清掉
|
||||||
if err := s.setTags(id, in.Tags); err != nil {
|
if in.Tags != nil || p.Kind == model.KindShort {
|
||||||
|
tags := in.Tags
|
||||||
|
if p.Kind == model.KindShort {
|
||||||
|
tags = nil
|
||||||
|
}
|
||||||
|
if err := s.setTags(id, tags); err != nil {
|
||||||
return p, err
|
return p, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,6 +365,14 @@ onBeforeRouteLeave(() => {
|
|||||||
|
|
||||||
// ---------- 标签 ----------
|
// ---------- 标签 ----------
|
||||||
|
|
||||||
|
// 标签是长文的组织方式;切到短文时把已选的清掉(后端落库时也会强制丢弃)
|
||||||
|
watch(
|
||||||
|
() => form.kind,
|
||||||
|
(k) => {
|
||||||
|
if (k === 'short') form.tags = []
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
function addTag() {
|
function addTag() {
|
||||||
const v = tagInput.value.trim().replace(/[,,]$/, '')
|
const v = tagInput.value.trim().replace(/[,,]$/, '')
|
||||||
if (!v) return
|
if (!v) return
|
||||||
@@ -848,7 +856,7 @@ const tbGroups = computed(() => [
|
|||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field">
|
<div v-if="form.kind !== 'short'" class="field">
|
||||||
<label>标签</label>
|
<label>标签</label>
|
||||||
<div v-if="form.tags.length" style="display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px;">
|
<div v-if="form.tags.length" style="display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px;">
|
||||||
<span v-for="t in form.tags" :key="t" class="chip">
|
<span v-for="t in form.tags" :key="t" class="chip">
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { computed, onMounted, ref } from 'vue'
|
|||||||
import { publicApi } from '../api'
|
import { publicApi } from '../api'
|
||||||
import { site } from '../site'
|
import { site } from '../site'
|
||||||
import { socialIcon } from '../socialIcons'
|
import { socialIcon } from '../socialIcons'
|
||||||
import { relativeDate } from '../utils'
|
import { relativeDate, stripTags, thumbURL } from '../utils'
|
||||||
|
|
||||||
// vivid 是单栏布局,右栏整体不渲染(省掉 latest/tags 两次请求)。
|
// vivid 是单栏布局,右栏整体不渲染(省掉 latest/tags 两次请求)。
|
||||||
const isVivid = computed(() => site.ui_id === 'vivid')
|
const isVivid = computed(() => site.ui_id === 'vivid')
|
||||||
@@ -27,6 +27,26 @@ const links = [
|
|||||||
const latest = ref([])
|
const latest = ref([])
|
||||||
const tags = ref([])
|
const tags = ref([])
|
||||||
|
|
||||||
|
// 短文没有标题,侧栏拿正文开头当标识(flomo/Twitter 的做法),
|
||||||
|
// 纯图片短文显示占位;有配图时右侧带一张小缩略图。
|
||||||
|
const EXCERPT_LEN = 22
|
||||||
|
function excerpt(p) {
|
||||||
|
if (p.kind !== 'short') return p.title || '无题'
|
||||||
|
// 先剥 <a>:贴链接的短文开头是 URL 本身,摘出来没有信息量;
|
||||||
|
// 剥完没字了(纯链接贴)就退到链接卡片的标题
|
||||||
|
const noLinks = (p.content_html || '').replace(/<a\b[^>]*>[\s\S]*?<\/a>/gi, ' ')
|
||||||
|
const text = stripTags(noLinks).replace(/\s+/g, ' ').trim()
|
||||||
|
if (text) return text.length > EXCERPT_LEN ? text.slice(0, EXCERPT_LEN) + '…' : text
|
||||||
|
if (p.link_card && p.link_card.title) {
|
||||||
|
const t = p.link_card.title
|
||||||
|
return t.length > EXCERPT_LEN ? t.slice(0, EXCERPT_LEN) + '…' : t
|
||||||
|
}
|
||||||
|
return p.images && p.images.length ? '📷 图片' : '短文'
|
||||||
|
}
|
||||||
|
function thumbOf(p) {
|
||||||
|
return p.kind === 'short' && p.images && p.images.length ? thumbURL(p.images[0], 160) : ''
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (isVivid.value) return
|
if (isVivid.value) return
|
||||||
try {
|
try {
|
||||||
@@ -52,12 +72,22 @@ onMounted(async () => {
|
|||||||
<p class="eyebrow">最近更新</p>
|
<p class="eyebrow">最近更新</p>
|
||||||
<ul class="list">
|
<ul class="list">
|
||||||
<li v-for="p in latest" :key="p.id">
|
<li v-for="p in latest" :key="p.id">
|
||||||
<RouterLink :to="`/post/${p.slug}`" class="row">
|
<RouterLink :to="`/post/${p.slug}`" class="row" :class="{ withThumb: thumbOf(p) }">
|
||||||
|
<span class="row-main">
|
||||||
<span class="title">
|
<span class="title">
|
||||||
{{ p.kind === 'short' ? '短文' : p.title || '无题' }}
|
{{ excerpt(p) }}
|
||||||
<span v-if="p.kind === 'short'" class="badge">短</span>
|
<span v-if="p.kind === 'short'" class="badge">短</span>
|
||||||
</span>
|
</span>
|
||||||
<span class="date">{{ relativeDate(p.published_at) }}</span>
|
<span class="date">{{ relativeDate(p.published_at) }}</span>
|
||||||
|
</span>
|
||||||
|
<img
|
||||||
|
v-if="thumbOf(p)"
|
||||||
|
class="thumb"
|
||||||
|
:src="thumbOf(p)"
|
||||||
|
alt=""
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
|
/>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -152,7 +182,9 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.row {
|
.row {
|
||||||
display: block;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
padding: 7px 0;
|
padding: 7px 0;
|
||||||
border-bottom: 1px dashed var(--line-soft);
|
border-bottom: 1px dashed var(--line-soft);
|
||||||
}
|
}
|
||||||
@@ -161,10 +193,27 @@ onMounted(async () => {
|
|||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 文字列吃满剩余宽度,缩略图固定在右 */
|
||||||
|
.row-main {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 1.7;
|
line-height: 1.7;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thumb {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--card);
|
||||||
|
border: 1px solid var(--line-soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
|
|||||||
Reference in New Issue
Block a user