511 lines
22 KiB
Vue
511 lines
22 KiB
Vue
<script setup>
|
||
const { data: posts } = await useFetch('/api/posts', {
|
||
default: () => []
|
||
})
|
||
|
||
const { data: tags } = await useFetch('/api/tags', {
|
||
default: () => []
|
||
})
|
||
|
||
const postFeedStyleStorageKey = 'POST_FEED_STYLE'
|
||
|
||
const postFeedStyleOpen = ref(false)
|
||
const postFeedStyle = ref('compact')
|
||
|
||
/**
|
||
* Latest 피드 보기 방식을 저장한다.
|
||
* @param {'list' | 'compact' | 'cards' | 'articles'} value - 보기 방식
|
||
* @returns {void}
|
||
*/
|
||
const setPostFeedStyle = (value) => {
|
||
postFeedStyle.value = value
|
||
|
||
if (import.meta.client) {
|
||
localStorage.setItem(postFeedStyleStorageKey, value)
|
||
}
|
||
}
|
||
|
||
const closePostFeedStyleMenu = () => {
|
||
postFeedStyleOpen.value = false
|
||
}
|
||
|
||
const onDocumentPointerDown = (event) => {
|
||
if (!postFeedStyleOpen.value) {
|
||
return
|
||
}
|
||
|
||
const target = /** @type {HTMLElement | null} */ (event.target instanceof HTMLElement ? event.target : null)
|
||
if (!target) {
|
||
closePostFeedStyleMenu()
|
||
return
|
||
}
|
||
|
||
if (target.closest('[data-feed-style-root]')) {
|
||
return
|
||
}
|
||
|
||
closePostFeedStyleMenu()
|
||
}
|
||
|
||
/**
|
||
* 태그 슬러그로 태그 정보 조회
|
||
* @param {string | undefined} slug - 태그 슬러그
|
||
* @returns {{name: string, color: string}} 태그 정보
|
||
*/
|
||
const getTagMeta = (slug) => {
|
||
if (!slug) {
|
||
return {
|
||
name: '',
|
||
color: '#4d4d4d'
|
||
}
|
||
}
|
||
|
||
const matchedTag = tags.value.find((item) => item.slug === slug)
|
||
|
||
return {
|
||
name: matchedTag?.name || String(slug).toUpperCase(),
|
||
color: matchedTag?.color || '#4d4d4d'
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Latest 목록 데이터 변환
|
||
* @param {Object} post - API 게시물
|
||
* @returns {Object} 화면 표시 데이터
|
||
*/
|
||
const mapLatestPost = (post) => {
|
||
const primaryTagSlug = post.tags?.[0]
|
||
const tagMeta = getTagMeta(primaryTagSlug)
|
||
|
||
return {
|
||
title: post.title,
|
||
excerpt: post.excerpt,
|
||
featuredImage: post.featuredImage,
|
||
tagName: tagMeta.name,
|
||
tagColor: tagMeta.color,
|
||
publishedAt: formatPostDate(post.publishedAt),
|
||
publishedAtIso: post.publishedAt || '',
|
||
to: `/post/${post.slug}`,
|
||
isFeatured: Boolean(post.isFeatured),
|
||
commentCount: Number(post.commentCount || 0)
|
||
}
|
||
}
|
||
|
||
const featuredPosts = computed(() => posts.value.filter((post) => post.isFeatured).slice(0, 6))
|
||
const latestPosts = computed(() => posts.value.map(mapLatestPost))
|
||
|
||
const featuredTrackRef = ref(null)
|
||
/** Featured 트랙이 스크롤 시작에 붙었는지 — 이전 화살표 비활성 */
|
||
const featuredAtStart = ref(true)
|
||
/** Featured 트랙이 스크롤 끝에 붙었는지 — 다음 화살표 비활성 */
|
||
const featuredAtEnd = ref(true)
|
||
|
||
let unbindFeaturedScroll = () => {}
|
||
|
||
/**
|
||
* Featured 가로 스크롤 위치에 따라 이전/다음 버튼 상태를 갱신한다.
|
||
* @param {HTMLElement | null} el - 스크롤 컨테이너
|
||
* @returns {void}
|
||
*/
|
||
const updateFeaturedScrollEdges = (el) => {
|
||
const target = el || featuredTrackRef.value
|
||
|
||
if (!target) {
|
||
featuredAtStart.value = true
|
||
featuredAtEnd.value = true
|
||
return
|
||
}
|
||
|
||
const { scrollLeft, scrollWidth, clientWidth } = target
|
||
const maxScroll = Math.max(0, scrollWidth - clientWidth)
|
||
const epsilon = 2
|
||
|
||
featuredAtStart.value = scrollLeft <= epsilon
|
||
featuredAtEnd.value = scrollLeft >= maxScroll - epsilon
|
||
}
|
||
|
||
watch(featuredTrackRef, (el) => {
|
||
unbindFeaturedScroll()
|
||
unbindFeaturedScroll = () => {}
|
||
|
||
if (!import.meta.client || !el) {
|
||
updateFeaturedScrollEdges(null)
|
||
return
|
||
}
|
||
|
||
const onScroll = () => {
|
||
updateFeaturedScrollEdges(el)
|
||
}
|
||
|
||
onScroll()
|
||
el.addEventListener('scroll', onScroll, { passive: true })
|
||
const resizeObserver = new ResizeObserver(onScroll)
|
||
resizeObserver.observe(el)
|
||
unbindFeaturedScroll = () => {
|
||
el.removeEventListener('scroll', onScroll)
|
||
resizeObserver.disconnect()
|
||
}
|
||
}, { immediate: true })
|
||
|
||
watch(featuredPosts, () => {
|
||
if (!import.meta.client) {
|
||
return
|
||
}
|
||
|
||
nextTick(() => {
|
||
updateFeaturedScrollEdges(featuredTrackRef.value)
|
||
})
|
||
})
|
||
|
||
onMounted(() => {
|
||
if (!import.meta.client) {
|
||
return
|
||
}
|
||
|
||
const storedStyle = localStorage.getItem(postFeedStyleStorageKey)
|
||
if (storedStyle === 'list' || storedStyle === 'compact' || storedStyle === 'cards' || storedStyle === 'articles') {
|
||
postFeedStyle.value = storedStyle
|
||
}
|
||
|
||
document.addEventListener('pointerdown', onDocumentPointerDown)
|
||
})
|
||
|
||
onBeforeUnmount(() => {
|
||
if (!import.meta.client) {
|
||
return
|
||
}
|
||
|
||
unbindFeaturedScroll()
|
||
document.removeEventListener('pointerdown', onDocumentPointerDown)
|
||
})
|
||
|
||
/**
|
||
* Featured 가로 트랙을 좌우로 이동한다.
|
||
* @param {'left' | 'right'} direction - 이동 방향
|
||
* @returns {void}
|
||
*/
|
||
const scrollFeatured = (direction) => {
|
||
if (!featuredTrackRef.value) {
|
||
return
|
||
}
|
||
|
||
if (direction === 'left' && featuredAtStart.value) {
|
||
return
|
||
}
|
||
|
||
if (direction === 'right' && featuredAtEnd.value) {
|
||
return
|
||
}
|
||
|
||
const firstCard = featuredTrackRef.value.querySelector('[data-featured-slide]')
|
||
const cardWidth = firstCard ? firstCard.getBoundingClientRect().width : 244
|
||
const gap = 24
|
||
const offset = direction === 'left' ? -(cardWidth + gap) : cardWidth + gap
|
||
|
||
featuredTrackRef.value.scrollBy({
|
||
left: offset,
|
||
behavior: 'smooth'
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<MainColumn>
|
||
<section class="py-6 px-6 md:py-8">
|
||
<div class="mx-auto flex max-w-[720px] flex-col-reverse gap-6">
|
||
<div class="z-[2] flex flex-col items-center justify-center gap-2 text-center">
|
||
<h1 class="text-xl font-semibold leading-[1.125] md:text-2xl">
|
||
Ideas <em>published</em> for meaningful conversation, <em>discussed</em> and shaped by the community
|
||
</h1>
|
||
<p class="max-w-md text-base leading-snug site-muted">
|
||
A modern Ghost theme for curated, community-driven publishing, where members join the conversation.
|
||
</p>
|
||
<form class="group relative mt-1 flex w-full max-w-xs flex-col items-start">
|
||
<fieldset class="flex w-full flex-wrap gap-2 text-sm">
|
||
<legend class="sr-only">Personal information</legend>
|
||
<input class="site-input flex-[2] rounded-[10px] px-3 py-1.5 text-sm" type="email" placeholder="Your email" aria-label="Your email">
|
||
<button class="site-button flex-1 cursor-pointer rounded-[10px] border border-[var(--site-invert)] bg-gradient-to-b from-[rgba(17,17,17,0.75)] to-[rgba(17,17,17,0.95)] px-3 py-1.5 font-medium text-[var(--site-invert-text)] hover:opacity-90" type="button">
|
||
Subscribe
|
||
</button>
|
||
</fieldset>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section v-if="featuredPosts.length" class="py-4 px-6">
|
||
<div class="mx-auto max-w-[720px]">
|
||
<div class="flex items-end justify-between gap-2 border-b border-[var(--site-line)] pb-2">
|
||
<h2 class="text-sm font-medium uppercase site-muted">Featured</h2>
|
||
<div class="flex justify-between gap-2">
|
||
<button
|
||
class="featured-nav-prev cursor-pointer p-1 text-[var(--site-text)] hover:opacity-75 disabled:cursor-not-allowed disabled:opacity-35 disabled:hover:opacity-35"
|
||
type="button"
|
||
aria-label="Featured 이전"
|
||
:disabled="featuredAtStart"
|
||
@click="scrollFeatured('left')"
|
||
>
|
||
‹
|
||
</button>
|
||
<button
|
||
class="featured-nav-next cursor-pointer p-1 text-[var(--site-text)] hover:opacity-75 disabled:cursor-not-allowed disabled:opacity-35 disabled:hover:opacity-35"
|
||
type="button"
|
||
aria-label="Featured 다음"
|
||
:disabled="featuredAtEnd"
|
||
@click="scrollFeatured('right')"
|
||
>
|
||
›
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div
|
||
ref="featuredTrackRef"
|
||
class="featured-posts-track mt-4 flex snap-x snap-mandatory gap-6 overflow-x-auto overscroll-x-contain scroll-smooth pb-1 touch-pan-x [-webkit-overflow-scrolling:touch] [--slides:1.4] sm:[--slides:1.6] lg:[--slides:2.6] [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
|
||
>
|
||
<NuxtLink
|
||
v-for="post in featuredPosts"
|
||
:key="`featured-${post.slug}`"
|
||
:to="`/post/${post.slug}`"
|
||
class="group relative block aspect-video w-[calc((100%-(24px*(var(--slides)-1)))/var(--slides))] shrink-0 snap-start overflow-hidden rounded-[10px]"
|
||
data-featured-slide
|
||
>
|
||
<img
|
||
v-if="post.featuredImage"
|
||
:src="post.featuredImage"
|
||
:alt="post.title"
|
||
class="h-full w-full object-cover brightness-75 contrast-125 transition-all duration-200 group-hover:brightness-90 group-hover:contrast-110"
|
||
loading="lazy"
|
||
>
|
||
<div
|
||
v-else
|
||
class="h-full w-full bg-[linear-gradient(135deg,#071b22,#5f6f85)]"
|
||
/>
|
||
<h3 class="absolute right-0 bottom-2.5 left-0 px-3 text-sm font-medium leading-tight text-white line-clamp-2">
|
||
{{ post.title }}
|
||
</h3>
|
||
</NuxtLink>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="py-4 px-6">
|
||
<div class="mx-auto max-w-[720px]">
|
||
<div class="flex items-end justify-between gap-2 border-b border-[var(--site-line)] pb-2">
|
||
<h2 class="text-sm font-medium uppercase site-muted">Latest</h2>
|
||
<div class="relative flex flex-col gap-1 text-sm font-medium" data-feed-style-root>
|
||
<button
|
||
class="site-input relative flex cursor-pointer items-center justify-center gap-1 rounded-[10px] border px-2 py-1.5 pr-1.5 leading-none hover:bg-[var(--site-panel)]"
|
||
type="button"
|
||
aria-label="피드 보기 방식 선택"
|
||
data-feed-style-toggle
|
||
@click="postFeedStyleOpen = !postFeedStyleOpen"
|
||
>
|
||
<span class="pointer-events-none" v-show="postFeedStyle === 'list'">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M9 6h11" />
|
||
<path d="M9 12h11" />
|
||
<path d="M9 18h11" />
|
||
<path d="M5 6v.01" />
|
||
<path d="M5 12v.01" />
|
||
<path d="M5 18v.01" />
|
||
</svg>
|
||
</span>
|
||
<span class="pointer-events-none" v-show="postFeedStyle === 'compact'">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M13 5h8" />
|
||
<path d="M13 9h5" />
|
||
<path d="M13 15h8" />
|
||
<path d="M13 19h5" />
|
||
<path d="M3 5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V5" />
|
||
<path d="M3 15a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-4" />
|
||
</svg>
|
||
</span>
|
||
<span class="pointer-events-none" v-show="postFeedStyle === 'cards'">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M4 6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6" />
|
||
<path d="M4 16a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-2" />
|
||
</svg>
|
||
</span>
|
||
<span class="pointer-events-none" v-show="postFeedStyle === 'articles'">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M3.06 13a9 9 0 1 0 .49-4.087" />
|
||
<path d="M3 4.001v5h5" />
|
||
<path d="M11 12a1 1 0 1 0 2 0a1 1 0 1 0-2 0" />
|
||
</svg>
|
||
</span>
|
||
<span class="pointer-events-none opacity-75">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="m6 9 6 6 6-6" />
|
||
</svg>
|
||
</span>
|
||
</button>
|
||
|
||
<menu
|
||
class="absolute top-9 right-0 z-10 flex w-44 flex-col gap-0.5 rounded-[10px] border border-[var(--site-line)] bg-[var(--site-bg)] p-1.5 shadow transition-[transform,opacity,visibility,scale] duration-200"
|
||
:class="postFeedStyleOpen ? 'visible translate-y-0 scale-100 opacity-100' : 'invisible -translate-y-3 scale-95 opacity-0'"
|
||
>
|
||
<li class="w-full">
|
||
<button class="flex w-full cursor-pointer items-center gap-1.5 rounded-[10px] px-2 py-1 hover:bg-[var(--site-panel)]" type="button" @click="setPostFeedStyle('list'); closePostFeedStyleMenu()">
|
||
<span class="pointer-events-none">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M9 6h11" />
|
||
<path d="M9 12h11" />
|
||
<path d="M9 18h11" />
|
||
<path d="M5 6v.01" />
|
||
<path d="M5 12v.01" />
|
||
<path d="M5 18v.01" />
|
||
</svg>
|
||
</span>
|
||
<span>List</span>
|
||
</button>
|
||
</li>
|
||
<li class="w-full">
|
||
<button class="flex w-full cursor-pointer items-center gap-1.5 rounded-[10px] px-2 py-1 hover:bg-[var(--site-panel)]" type="button" @click="setPostFeedStyle('compact'); closePostFeedStyleMenu()">
|
||
<span class="pointer-events-none">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M13 5h8" />
|
||
<path d="M13 9h5" />
|
||
<path d="M13 15h8" />
|
||
<path d="M13 19h5" />
|
||
<path d="M3 5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V5" />
|
||
<path d="M3 15a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-4" />
|
||
</svg>
|
||
</span>
|
||
<span>Compact</span>
|
||
</button>
|
||
</li>
|
||
<li class="w-full">
|
||
<button class="flex w-full cursor-pointer items-center gap-1.5 rounded-[10px] px-2 py-1 hover:bg-[var(--site-panel)]" type="button" @click="setPostFeedStyle('cards'); closePostFeedStyleMenu()">
|
||
<span class="pointer-events-none">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M4 6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6" />
|
||
<path d="M4 16a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-2" />
|
||
</svg>
|
||
</span>
|
||
<span>Cards</span>
|
||
</button>
|
||
</li>
|
||
<li class="w-full">
|
||
<button class="flex w-full cursor-pointer items-center gap-1.5 rounded-[10px] px-2 py-1 hover:bg-[var(--site-panel)]" type="button" @click="setPostFeedStyle('articles'); closePostFeedStyleMenu()">
|
||
<span class="pointer-events-none">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M3.06 13a9 9 0 1 0 .49-4.087" />
|
||
<path d="M3 4.001v5h5" />
|
||
<path d="M11 12a1 1 0 1 0 2 0a1 1 0 1 0-2 0" />
|
||
</svg>
|
||
</span>
|
||
<span>Default</span>
|
||
</button>
|
||
</li>
|
||
</menu>
|
||
</div>
|
||
</div>
|
||
<div class="mb-8 flex flex-col">
|
||
<div
|
||
class="flex flex-col divide-y divide-[var(--site-line)]"
|
||
:class="postFeedStyle === 'cards' ? 'divide-y-0 gap-4 sm:grid sm:grid-cols-2 sm:gap-4' : ''"
|
||
>
|
||
<article
|
||
v-for="post in latestPosts"
|
||
:key="post.to"
|
||
class="group relative overflow-hidden"
|
||
:class="postFeedStyle === 'cards' ? 'rounded-[10px] border border-[var(--site-line)] p-3' : 'flex flex-row gap-3 py-4'"
|
||
>
|
||
<NuxtLink
|
||
:to="post.to"
|
||
class="relative flex-1"
|
||
:class="postFeedStyle === 'cards' ? 'mb-3 block aspect-video w-full' : 'aspect-square min-w-16 sm:aspect-video'"
|
||
>
|
||
<figure class="overflow-hidden rounded-[10px]">
|
||
<img
|
||
v-if="post.featuredImage"
|
||
:src="post.featuredImage"
|
||
:alt="post.title"
|
||
class="w-full rounded-[inherit] object-cover transition-opacity duration-200 group-hover:opacity-90"
|
||
:class="postFeedStyle === 'cards' ? 'aspect-video' : 'aspect-square sm:aspect-video'"
|
||
loading="lazy"
|
||
>
|
||
<div
|
||
v-else
|
||
class="w-full rounded-[inherit] bg-[linear-gradient(135deg,#253444,#8f9dad)]"
|
||
:class="postFeedStyle === 'cards' ? 'aspect-video' : 'aspect-square sm:aspect-video'"
|
||
/>
|
||
</figure>
|
||
</NuxtLink>
|
||
|
||
<div
|
||
class="relative"
|
||
:class="postFeedStyle === 'cards' ? '' : 'flex-[3] md:flex-[4]'"
|
||
>
|
||
<div
|
||
class="flex h-full flex-col gap-1.5"
|
||
:class="postFeedStyle === 'cards' ? '' : ''"
|
||
>
|
||
<h2 class="max-w-[90%] text-sm font-medium leading-tight">
|
||
<NuxtLink :to="post.to" class="flex items-center transition-opacity duration-200 hover:opacity-75">
|
||
<span v-if="post.isFeatured" class="post-feed__featured-icon mr-1 inline-flex h-4 w-4 items-center justify-center text-[var(--site-accent)]">
|
||
<svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M13 3v7h6l-8 11v-7H5l8-11" />
|
||
</svg>
|
||
</span>
|
||
{{ post.title }}
|
||
</NuxtLink>
|
||
</h2>
|
||
|
||
<p
|
||
class="flex-1 text-[0.8rem] leading-tight site-muted"
|
||
:class="postFeedStyle === 'list' ? 'line-clamp-3' : postFeedStyle === 'articles' ? 'line-clamp-4' : 'line-clamp-2'"
|
||
>
|
||
{{ post.excerpt }}
|
||
</p>
|
||
|
||
<div class="flex flex-wrap items-center gap-2 text-xs site-muted sm:gap-1.5">
|
||
<time v-if="post.publishedAt" :datetime="post.publishedAtIso">{{ post.publishedAt }}</time>
|
||
<template v-if="post.tagName">
|
||
<span v-if="post.publishedAt" class="text-[var(--site-line)]">/</span>
|
||
<span
|
||
class="rounded-md px-1.5 py-px font-medium text-[var(--site-text)]"
|
||
:style="{ backgroundColor: `${post.tagColor}1a` }"
|
||
>
|
||
{{ post.tagName }}
|
||
</span>
|
||
</template>
|
||
<span v-if="post.publishedAt || post.tagName" class="text-[var(--site-line)]">/</span>
|
||
<span class="flex items-center gap-1">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="-mt-px">
|
||
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
|
||
</svg>
|
||
<span>{{ post.commentCount }}</span>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<button
|
||
class="absolute top-0 right-0 flex cursor-pointer items-center gap-1 hover:opacity-75"
|
||
:class="postFeedStyle === 'cards' ? '' : 'md:top-auto md:right-0 md:bottom-0 md:invisible md:opacity-0 md:transition-[opacity,visibility] md:duration-200 md:group-hover:visible md:group-hover:opacity-100'"
|
||
type="button"
|
||
aria-label="Share this post"
|
||
>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
viewBox="0 0 24 24"
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="2"
|
||
stroke-linecap="round"
|
||
stroke-linejoin="round"
|
||
class="h-4 w-4"
|
||
>
|
||
<path d="M17 7 7 17" />
|
||
<path d="M8 7h9v9" />
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</MainColumn>
|
||
</template>
|