memi-board 0.63.0 → 0.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +283 -269
- package/dist/index.js.map +1 -1
- package/dist/runtime/components/Detail.vue +2 -8
- package/dist/runtime/components/ListCard.vue +22 -1
- package/dist/runtime/components/ListDefault.vue +32 -2
- package/dist/utils/customFields.d.ts +6 -0
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import MemiBoardSurface from './BoardSurface.vue'
|
|
|
3
3
|
import { ref, computed, onBeforeUnmount, onMounted, watch } from 'vue'
|
|
4
4
|
import Youtube from '@tiptap/extension-youtube'
|
|
5
5
|
import type { PostModel } from 'memi-board/runtime'
|
|
6
|
-
import { displayPostContent, displayPostTitle, POST_EDIT_LIMIT,
|
|
6
|
+
import { displayPostContent, displayPostTitle, POST_EDIT_LIMIT, extendEntries, renderMarkdownToHtml, useMemiBoardI18n } from 'memi-board/runtime'
|
|
7
7
|
import { useMemiBoardPost, useMemiBoardPosts } from 'memi-board/runtime'
|
|
8
8
|
import { useMemiBoardAuth } from 'memi-board/runtime'
|
|
9
9
|
import { useMemiBoardSettings } from 'memi-board/runtime'
|
|
@@ -49,13 +49,7 @@ const { recordView } = useMemiBoardViews()
|
|
|
49
49
|
const { post, pending: loading } = useMemiBoardPost(() => props.boardId, computed(() => props.postId))
|
|
50
50
|
const notFound = computed(() => !loading.value && !post.value)
|
|
51
51
|
const isDraft = computed(() => post.value?.isPublished === false)
|
|
52
|
-
const shownExtend = computed(() =>
|
|
53
|
-
const values = readExtend(post.value?.extend)
|
|
54
|
-
return (getBoard(props.boardId)?.customFields ?? []).flatMap((field) => {
|
|
55
|
-
const value = values[field.key]
|
|
56
|
-
return value ? [{ key: field.key, label: field.label, value }] : []
|
|
57
|
-
})
|
|
58
|
-
})
|
|
52
|
+
const shownExtend = computed(() => extendEntries(post.value?.extend, getBoard(props.boardId)?.customFields))
|
|
59
53
|
const deleting = ref(false)
|
|
60
54
|
const publishing = ref(false)
|
|
61
55
|
const pinning = ref(false)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import MemiBoardSurface from './BoardSurface.vue'
|
|
3
3
|
import { resolveComponent } from 'vue'
|
|
4
4
|
import type { PostModel } from 'memi-board/runtime'
|
|
5
|
-
import { displayPostSummary, displayPostTitle, useMemiBoardI18n } from 'memi-board/runtime'
|
|
5
|
+
import { displayPostSummary, displayPostTitle, extendEntries, useMemiBoardI18n, useMemiBoardSettings } from 'memi-board/runtime'
|
|
6
6
|
import MemiBoardAuthorMenu from './AuthorMenu.vue'
|
|
7
7
|
|
|
8
8
|
defineProps<{
|
|
@@ -17,6 +17,14 @@ defineProps<{
|
|
|
17
17
|
const emit = defineEmits<{ select: [post: PostModel] }>()
|
|
18
18
|
const NuxtLink = resolveComponent('NuxtLink')
|
|
19
19
|
const { t, locale, formatRelativeDate } = useMemiBoardI18n()
|
|
20
|
+
const { getBoard } = useMemiBoardSettings()
|
|
21
|
+
|
|
22
|
+
/** 목록에서는 필드를 이만큼만 보여 주고 나머지는 +N 으로 줄인다. */
|
|
23
|
+
const EXTEND_SHOWN = 3
|
|
24
|
+
function extendOf(post: PostModel) {
|
|
25
|
+
const entries = extendEntries(post.extend, getBoard(post.boardId || post.category || '')?.customFields)
|
|
26
|
+
return { shown: entries.slice(0, EXTEND_SHOWN), more: Math.max(0, entries.length - EXTEND_SHOWN), all: entries }
|
|
27
|
+
}
|
|
20
28
|
|
|
21
29
|
function titleOf(post: PostModel) {
|
|
22
30
|
return displayPostTitle(post, locale.value).trim() || displayPostSummary(post, locale.value).trim() || t('list.photo')
|
|
@@ -60,6 +68,19 @@ function image(post: PostModel): string | undefined {
|
|
|
60
68
|
<p v-if="summaryOf(post)" class="line-clamp-3 break-words whitespace-pre-line text-sm leading-relaxed text-muted">
|
|
61
69
|
{{ summaryOf(post) }}
|
|
62
70
|
</p>
|
|
71
|
+
<dl v-if="extendOf(post).shown.length" class="grid grid-cols-[auto_minmax(0,1fr)] gap-x-3 gap-y-1 rounded-lg bg-elevated/50 px-3 py-2 text-xs">
|
|
72
|
+
<template v-for="field in extendOf(post).shown" :key="field.key">
|
|
73
|
+
<dt class="max-w-28 truncate text-muted">{{ field.label }}</dt>
|
|
74
|
+
<dd class="truncate font-medium text-default" :title="field.value">{{ field.value }}</dd>
|
|
75
|
+
</template>
|
|
76
|
+
<dd
|
|
77
|
+
v-if="extendOf(post).more"
|
|
78
|
+
class="col-span-2 text-dimmed"
|
|
79
|
+
:title="extendOf(post).all.slice(3).map(field => `${field.label}: ${field.value}`).join('\n')"
|
|
80
|
+
>
|
|
81
|
+
+{{ extendOf(post).more }}
|
|
82
|
+
</dd>
|
|
83
|
+
</dl>
|
|
63
84
|
<p class="mt-auto pt-1 text-xs text-dimmed">
|
|
64
85
|
<time :datetime="post.createdAt?.toDate?.().toISOString()">{{ formatRelativeDate(post.createdAt, now) }}</time>
|
|
65
86
|
<template v-if="(post.commentCount ?? 0) > 0"> · {{ t('list.commentCount', { count: post.commentCount }) }}</template>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import MemiBoardSurface from './BoardSurface.vue'
|
|
3
3
|
import { resolveComponent } from 'vue'
|
|
4
4
|
import type { PostModel } from 'memi-board/runtime'
|
|
5
|
-
import { displayPostSummary, displayPostTitle, useMemiBoardI18n, useMemiBoardSettings } from 'memi-board/runtime'
|
|
5
|
+
import { displayPostSummary, displayPostTitle, extendEntries, useMemiBoardI18n, useMemiBoardSettings } from 'memi-board/runtime'
|
|
6
6
|
import MemiBoardAuthorMenu from './AuthorMenu.vue'
|
|
7
7
|
|
|
8
8
|
withDefaults(defineProps<{
|
|
@@ -15,7 +15,7 @@ withDefaults(defineProps<{
|
|
|
15
15
|
authorCommentsTo?: (authorUid: string) => string | undefined
|
|
16
16
|
}>(), { showCategory: true })
|
|
17
17
|
const emit = defineEmits<{ select: [post: PostModel] }>()
|
|
18
|
-
const { categoryLabel } = useMemiBoardSettings()
|
|
18
|
+
const { categoryLabel, getBoard } = useMemiBoardSettings()
|
|
19
19
|
const { t, locale, formatRelativeDate, formatTimestampDetails } = useMemiBoardI18n()
|
|
20
20
|
|
|
21
21
|
function titleOf(post: PostModel) {
|
|
@@ -29,6 +29,13 @@ function summaryOf(post: PostModel) {
|
|
|
29
29
|
}
|
|
30
30
|
const NuxtLink = resolveComponent('NuxtLink')
|
|
31
31
|
|
|
32
|
+
/** 목록에서는 필드를 이만큼만 보여 주고 나머지는 +N 으로 줄인다. */
|
|
33
|
+
const EXTEND_SHOWN = 3
|
|
34
|
+
function extendOf(post: PostModel) {
|
|
35
|
+
const entries = extendEntries(post.extend, getBoard(post.boardId || post.category || '')?.customFields)
|
|
36
|
+
return { shown: entries.slice(0, EXTEND_SHOWN), more: Math.max(0, entries.length - EXTEND_SHOWN), all: entries }
|
|
37
|
+
}
|
|
38
|
+
|
|
32
39
|
function image(post: PostModel): string | undefined {
|
|
33
40
|
return post.previewImage || post.attachments?.find(item => item.type.startsWith('image/'))?.url
|
|
34
41
|
}
|
|
@@ -88,6 +95,29 @@ function image(post: PostModel): string | undefined {
|
|
|
88
95
|
>
|
|
89
96
|
{{ summaryOf(post) }}
|
|
90
97
|
</p>
|
|
98
|
+
<div v-if="extendOf(post).shown.length" class="flex min-w-0 flex-wrap items-center gap-1 pt-0.5">
|
|
99
|
+
<UBadge
|
|
100
|
+
v-for="field in extendOf(post).shown"
|
|
101
|
+
:key="field.key"
|
|
102
|
+
color="neutral"
|
|
103
|
+
variant="outline"
|
|
104
|
+
size="sm"
|
|
105
|
+
class="max-w-48 min-w-0 font-normal"
|
|
106
|
+
:title="`${field.label}: ${field.value}`"
|
|
107
|
+
>
|
|
108
|
+
<span class="shrink-0 text-dimmed">{{ field.label }}</span>
|
|
109
|
+
<span class="truncate text-default">{{ field.value }}</span>
|
|
110
|
+
</UBadge>
|
|
111
|
+
<UBadge
|
|
112
|
+
v-if="extendOf(post).more"
|
|
113
|
+
color="neutral"
|
|
114
|
+
variant="soft"
|
|
115
|
+
size="sm"
|
|
116
|
+
class="font-normal"
|
|
117
|
+
:label="`+${extendOf(post).more}`"
|
|
118
|
+
:title="extendOf(post).all.slice(3).map(field => `${field.label}: ${field.value}`).join('\n')"
|
|
119
|
+
/>
|
|
120
|
+
</div>
|
|
91
121
|
</div>
|
|
92
122
|
|
|
93
123
|
<div
|
|
@@ -31,3 +31,9 @@ export declare function prepareCustomFields(fields: BoardCustomField[] | undefin
|
|
|
31
31
|
export declare function readExtend(value: unknown): Record<string, string>;
|
|
32
32
|
/** 보드에 선언된 키의 값만 모은다. 비어 있는 칸은 저장하지 않는다. */
|
|
33
33
|
export declare function extendForFields(values: Record<string, string>, fields: BoardCustomField[]): Record<string, string>;
|
|
34
|
+
/** 글의 extend 를 보드 필드 순서대로, 값이 있는 것만 이름과 함께 돌려준다. */
|
|
35
|
+
export declare function extendEntries(extend: unknown, fields: BoardCustomField[] | undefined): Array<{
|
|
36
|
+
key: string;
|
|
37
|
+
label: string;
|
|
38
|
+
value: string;
|
|
39
|
+
}>;
|