Skip to content

Commit

Permalink
Rewrite PostItem element in TS
Browse files Browse the repository at this point in the history
  • Loading branch information
man90es committed Mar 11, 2024
1 parent 6dbc738 commit ae51abd
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 90 deletions.
17 changes: 6 additions & 11 deletions src/components/misc/PostAttachment.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
<template>
<div :class="$style.root">
<img :class="{ [$style.thumbnail]: true, [$style.blurred]: isNSFW }" :src="thumbSrc" :height="API.thumb.height" :width="API.thumb.width" @click="handleClick" loading="lazy" />
<img :class="{ [$style.thumbnail]: true, [$style.blurred]: isNSFW }" :src="thumbSrc" :height="API?.thumb?.height" :width="API?.thumb?.width" @click="handleClick" loading="lazy" />
<img :class="$style.videoMarker" src="@/assets/icons/play_circle.svg" v-if="isVideo" />
</div>
</template>
<script setup lang="ts">
import { computed, inject } from "vue"
import type { Post } from "@/store"
import type FKClient from "@bakaso/fkclient"
const API = inject("API")
const API = inject<FKClient>("API")
const props = defineProps<{ file: Post["attachments"][number] }>()
const props = defineProps<{
file: {
hash: string,
mime: string,
modifiers?: string[],
}
}>()
const thumbSrc = computed(() => `${API.thumb.path}${props.file.hash}.${API.thumb.format}`)
const thumbSrc = computed(() => `${API?.thumb?.path}${props.file.hash}.${API?.thumb?.format}`)
const isNSFW = computed(() => props.file.modifiers?.includes("NSFW"))
const isVideo = computed(() => "video" == props.file.mime?.split("/")[0])
Expand Down
145 changes: 67 additions & 78 deletions src/components/misc/PostItem.vue
Original file line number Diff line number Diff line change
@@ -1,149 +1,138 @@
<template>
<article v-if="![postId, post].includes()" :class="{ selected: marks.selected }">
<div class="postDetails">
<img v-if="marks.bookmarked" class="icon pre-icon" src="@/assets/icons/star.svg" />
<img v-if="props.pinned" class="icon pre-icon" src="@/assets/icons/push_pin.svg" />
<img v-if="post.modifiers?.includes('sage')" class="icon pre-icon" src="@/assets/icons/down.svg" />
<a class="refLink" @click="handleRefLinkClick">
<span class="subject" v-if="post.subject">{{ formattedSubject }}</span> #{{ post.number }}
<article v-if="post !== undefined" :class="{ [$style.root]: true, [$style.selected]: marks?.selected }">
<div :class="$style.postDetails">
<img v-if="marks?.bookmarked" class="icon" :class="$style.preIcon" src="@/assets/icons/star.svg" />
<img v-if="props.pinned" class="icon" :class="$style.preIcon" src="@/assets/icons/push_pin.svg" />
<img v-if="post?.modifiers?.includes('sage')" class="icon" :class="$style.preIcon" src="@/assets/icons/down.svg" />
<a @click="handleRefLinkClick">
<span :class="$style.subject" v-if="post?.subject">{{ formattedSubject }}</span>
#{{ post?.number }}
</a>
<button>
<img class="icon" src="@/assets/icons/menu.svg" @click="toggleMenu" />
</button>
<PostMenu v-if="menuVisible" :postId="postId" @cancel="toggleMenu" />
<PostMenu v-if="menuVisible && postId" :postId="postId" @cancel="toggleMenu" />
<button>
<img class="icon" src="@/assets/icons/reply.svg" @click="handleReplyClick" />
</button>
<time :title="preciseDate">{{ prettyDate }}</time>
<span v-if="settings.debug">b:"{{ thread?.boardName }}" tid:{{ post.threadId }} pid:{{ postId }}</span>
<time :class="$style.time" :title="preciseDate">{{ prettyDate }}</time>
<span v-if="settings.debug">b:"{{ thread?.boardName }}" tid:{{ post?.threadId }} pid:{{ postId }}</span>
</div>
<div v-if="!marks.hidden">
<div v-if="post.attachments" class="attachments">
<PostAttachment v-for="(file, index) in post.attachments" :file="file" :key="index" />
<div v-if="!marks?.hidden">
<div v-if="post?.attachments" :class="$style.attachments">
<PostAttachment v-for="file, i in post.attachments" :file="file" :key="i" />
</div>
<p v-if="post.text" v-html="parsedText" />
<PostRepliesList v-if="post?.replies?.length > 0" :replies="post.replies" />
<p :class="$style.text" v-if="post?.text" v-html="parsedText" />
<PostRepliesList v-if="post?.replies?.length" :replies="post.replies" />
</div>
</article>
</template>
<script setup>
<script setup lang="ts">
import { computed, inject, ref, watch } from "vue"
import { PostAttachment, PostMenu } from "@/components/misc"
import { PostAttachment, PostMenu, PostRepliesList } from "@/components/misc"
import { truncateString, renderMarkup, getPrettyTimeDelta } from "@/utils"
import { usePostMarksStore } from "@/stores/postMarks"
import { usePostMarksStore, useSettingsStore } from "@/stores"
import { useRouter } from "vue-router"
import { useSettingsStore } from "@/stores/settings"
import { useStore } from "vuex"
import PostRepliesList from "./PostRepliesList"
const API = inject("API")
const props = defineProps({
pinned: {
default: false,
type: Boolean,
},
postId: {
required: true,
type: Number,
},
})
import type { Post, StoreState } from "@/store"
import type FKClient from "@bakaso/fkclient"
const API = inject<FKClient>("API")
const props = defineProps<{ pinned?: boolean, postId: number }>()
const postMarksStore = usePostMarksStore()
const router = useRouter()
const settings = useSettingsStore()
const store = useStore()
const store = useStore<StoreState>()
const menuVisible = ref(false)
function toggleMenu() {
menuVisible.value = !menuVisible.value
}
const post = computed(() => store.state.posts[props.postId])
const parsedText = computed(() => renderMarkup(post.value.text || ""))
const formattedSubject = computed(() => truncateString(post.value.subject, 55))
const thread = computed(() => store.state.threads[post.value.threadId])
const prettyDate = computed(() => getPrettyTimeDelta(new Date(post.value.created)))
const preciseDate = computed(() => new Date(post.value.created).toLocaleString("en-GB"))
const post = computed<Post | undefined>(() => store.state.posts[props.postId] ?? undefined)
const parsedText = computed<string>(() => renderMarkup(post.value?.text || ""))
const formattedSubject = computed<string>(() => truncateString(post.value?.subject ?? "", 55))
const thread = computed(() => post.value?.threadId ? store.state.threads[post.value.threadId] : undefined)
const prettyDate = computed(() => post.value?.created ? getPrettyTimeDelta(new Date(post.value.created)) : undefined)
const preciseDate = computed(() => post.value?.created ? new Date(post.value.created).toLocaleString("en-GB") : undefined)
const marks = computed(() => postMarksStore.postMarks(props.postId))
function handleReplyClick() {
window.emitter.emit("post-reply-button-click", {
boardName: thread.value.boardName,
postNumber: post.value.number,
threadId: post.value.threadId,
threadNumber: thread.value.head.number,
boardName: thread.value?.boardName,
postNumber: post.value?.number,
threadId: post.value?.threadId,
threadNumber: thread.value?.head.number,
})
}
function handleRefLinkClick() {
router.push({
name: "thread",
params: {
boardName: thread.value.boardName,
threadId: post.value.threadId,
boardName: thread.value?.boardName,
threadId: post.value?.threadId,
},
})
}
watch(() => post.value, (newValue, oldValue) => {
if (undefined === thread.value && undefined === oldValue && undefined !== newValue) {
API.thread.request({ threadId: post.value.threadId })
API?.thread.request({ threadId: post.value?.threadId })
}
})
if (undefined === post.value) {
API.post.request({ postId: props.postId })
API?.post.request({ postId: props.postId })
}
</script>
<style scoped lang="scss">
article {
<style module>
.root {
background-color: var(--card-color);
border: 1px solid transparent;
margin: calc(var(--gap-size) - 1px) 0;
padding: var(--gap-size);
border: 1px solid transparent;
&.selected {
border-color: var(--link-hover-color);
}
&:first-child {
background-color: var(--card-color);
}
&:not(:first-child) {
background-color: var(--card-secondary-color);
margin-left: calc(var(--gap-size) * 4);
}
}
.postDetails {
position: relative;
}
.postDetails {
position: relative;
}
time {
position: absolute;
right: 0;
color: var(--text-secondary-color);
font-size: 0.9rem;
cursor: default;
}
.time {
color: var(--text-secondary-color);
cursor: default;
font-size: 0.9rem;
position: absolute;
right: 0;
}
.subject {
color: var(--text-secondary-color);
}
.subject {
color: var(--text-secondary-color);
}
.attachments {
display: flex;
gap: var(--gap-size);
}
.attachments {
display: flex;
gap: var(--gap-size);
}
p {
margin: 0;
}
.text {
margin: 0;
}
.icon.pre-icon {
vertical-align: middle;
height: 1.3em;
}
.preIcon {
height: 1.3rem;
vertical-align: sub;
}
</style>
1 change: 1 addition & 0 deletions src/components/misc/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as ModalShell } from "./ModalShell.vue"
export { default as PostAttachment } from "./PostAttachment.vue"
export { default as PostMenu } from "./PostMenu.vue"
export { default as PostRepliesList } from "./PostRepliesList.vue"
export { default as ToggleSwitch } from "./ToggleSwitch.vue"
11 changes: 10 additions & 1 deletion src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,23 @@ export type Thread = {
}

export type Post = {
attachments: Array<{
hash: string,
mime: string,
modifiers?: string[],
}>
created: string
id: number
number: number
threadId: Thread["id"]
modifiers?: string[]
replies: Array<{
boardName: Board["name"]
number: Post["number"]
threadId: Thread["id"]
}>
subject: string
text: string
threadId: Thread["id"]
}

export type StoreState = {
Expand Down

0 comments on commit ae51abd

Please sign in to comment.