v1.2.9: 라이브 에디터·홈 피드·메인 커버 개선
라이브 모드 코드/콜아웃/토글 편집, 슬래시 명령, 홈 Latest List·Compact·Cards 보기, 사이트 설정 메인 화면 커버(720px) 및 HomeHero 반영. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
58
components/site/HomeHero.vue
Normal file
58
components/site/HomeHero.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
/** 커버 이미지 URL */
|
||||
imageUrl: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/** 오버레이 제목 */
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/** 오버레이 본문 */
|
||||
text: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
/** @type {import('vue').ComputedRef<boolean>} */
|
||||
const hasOverlay = computed(() => Boolean(props.title?.trim() || props.text?.trim()))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
v-if="imageUrl"
|
||||
class="home-hero relative mx-auto w-full max-w-[720px] overflow-hidden rounded-[10px]"
|
||||
data-home-hero
|
||||
>
|
||||
<div class="home-hero__frame relative aspect-[720/215] w-full bg-[var(--site-panel)]">
|
||||
<img
|
||||
class="home-hero__cover absolute inset-0 h-full w-full object-cover"
|
||||
:src="imageUrl"
|
||||
alt=""
|
||||
loading="eager"
|
||||
>
|
||||
<div
|
||||
v-if="hasOverlay"
|
||||
class="home-hero__overlay pointer-events-none absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/70 via-black/35 to-transparent px-4 pb-4 pt-12 sm:px-5 sm:pb-5"
|
||||
>
|
||||
<div class="home-hero__overlay-inner flex flex-col items-start gap-1 text-left">
|
||||
<h2
|
||||
v-if="title"
|
||||
class="home-hero__title text-base font-semibold leading-snug text-white sm:text-lg"
|
||||
>
|
||||
{{ title }}
|
||||
</h2>
|
||||
<p
|
||||
v-if="text"
|
||||
class="home-hero__text max-w-[32rem] text-sm leading-relaxed text-white/85"
|
||||
>
|
||||
{{ text }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -8,16 +8,15 @@ defineProps({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<article class="post-card site-section site-panel-hover">
|
||||
<article class="post-card site-section site-panel-hover group">
|
||||
<div class="post-card__body site-section-body flex gap-4">
|
||||
<img
|
||||
v-if="post.featuredImage"
|
||||
class="post-card__thumb h-20 w-36 shrink-0 rounded-lg bg-surface object-cover"
|
||||
:src="post.featuredImage"
|
||||
:alt="post.title"
|
||||
loading="lazy"
|
||||
>
|
||||
<div v-else class="post-card__thumb h-20 w-36 shrink-0 rounded-lg bg-[linear-gradient(135deg,#06333a,#f4a261)]" />
|
||||
<PostCardMedia
|
||||
:to="post.to"
|
||||
:title="post.title"
|
||||
:featured-image="post.featuredImage"
|
||||
link-class="h-20 w-36 shrink-0"
|
||||
aspect-class="h-full w-full"
|
||||
/>
|
||||
<div class="post-card__content min-w-0">
|
||||
<h2 class="post-card__title text-base font-semibold leading-tight">
|
||||
<NuxtLink class="post-card__title-link site-interactive hover:opacity-70" :to="post.to">
|
||||
|
||||
62
components/site/PostCardMedia.vue
Normal file
62
components/site/PostCardMedia.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
/** 게시물 링크 */
|
||||
to: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
/** 게시물 제목 */
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
/** 대표 이미지 URL */
|
||||
featuredImage: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/** 썸네일 비율·크기 Tailwind 클래스 */
|
||||
aspectClass: {
|
||||
type: String,
|
||||
default: 'aspect-square sm:aspect-video'
|
||||
},
|
||||
/** 링크 래퍼 추가 클래스 */
|
||||
linkClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/** 이미지 추가 클래스 */
|
||||
imageClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NuxtLink
|
||||
:to="to"
|
||||
class="post-card-media relative block"
|
||||
:class="linkClass"
|
||||
data-post-card-media
|
||||
>
|
||||
<figure class="post-card-media__figure overflow-hidden rounded-[10px]">
|
||||
<img
|
||||
v-if="featuredImage"
|
||||
class="post-card-media__image w-full rounded-[inherit] object-cover transition-opacity duration-200 group-hover:opacity-90"
|
||||
:class="[aspectClass, imageClass]"
|
||||
:src="featuredImage"
|
||||
:alt="title"
|
||||
loading="lazy"
|
||||
>
|
||||
<span
|
||||
v-else
|
||||
class="post-card-media__placeholder flex w-full items-center justify-center rounded-[inherit] bg-[#F7F4EF] p-4 text-center text-xs leading-snug text-[var(--site-muted)] transition-opacity duration-200 group-hover:opacity-90"
|
||||
:class="aspectClass"
|
||||
:aria-label="title"
|
||||
>
|
||||
<span class="post-card-media__placeholder-text line-clamp-4">{{ title }}</span>
|
||||
</span>
|
||||
</figure>
|
||||
</NuxtLink>
|
||||
</template>
|
||||
@@ -166,14 +166,6 @@ onBeforeUnmount(() => {
|
||||
@click.prevent="toggleMenu"
|
||||
>
|
||||
<span v-if="menuOpen" class="site-header__menu-icon pointer-events-none">
|
||||
<svg class="block h-6 w-6 group-hover:hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path d="M6 21a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h12a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H6Zm12-16h-8v14h8a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1Z" />
|
||||
</svg>
|
||||
<svg class="hidden h-6 w-6 group-hover:block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path d="M18 3a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h12Zm0 2h-9v14h9a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1Zm-2.3 4.3a1 1 0 0 1 0 1.4L14.4 12l1.3 1.3a1 1 0 0 1-1.4 1.4l-2-2a1 1 0 0 1 0-1.4l2-2a1 1 0 0 1 1.4 0Z" />
|
||||
</svg>
|
||||
</span>
|
||||
<span v-else class="site-header__menu-icon pointer-events-none">
|
||||
<svg class="block h-6 w-6 group-hover:hidden" 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" aria-hidden="true">
|
||||
<path d="M4 6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6Z" />
|
||||
<path d="M9 4v16" />
|
||||
@@ -184,6 +176,14 @@ onBeforeUnmount(() => {
|
||||
<path d="m14 10 2 2-2 2" />
|
||||
</svg>
|
||||
</span>
|
||||
<span v-else class="site-header__menu-icon pointer-events-none">
|
||||
<svg class="block h-6 w-6 group-hover:hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path d="M6 21a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h12a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H6Zm12-16h-8v14h8a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1Z" />
|
||||
</svg>
|
||||
<svg class="hidden h-6 w-6 group-hover:block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path d="M18 3a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h12Zm0 2h-9v14h9a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1Zm-2.3 4.3a1 1 0 0 1 0 1.4L14.4 12l1.3 1.3a1 1 0 0 1-1.4 1.4l-2-2a1 1 0 0 1 0-1.4l2-2a1 1 0 0 1 1.4 0Z" />
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<span class="min-w-0 truncate">{{ siteSettings.title }}</span>
|
||||
</NuxtLink>
|
||||
@@ -195,7 +195,13 @@ onBeforeUnmount(() => {
|
||||
aria-label="검색 열기"
|
||||
@click="openSearchModal"
|
||||
>
|
||||
<span class="site-header__search-icon mr-2 text-lg leading-none">⌕</span>
|
||||
<span class="site-header__search-icon mr-2 text-lg leading-none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-search" width="16" height="16" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<circle cx="10" cy="10" r="7"></circle>
|
||||
<line x1="21" y1="21" x2="15" y2="15"></line>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="site-header__search-text site-soft">Search</span>
|
||||
<span class="site-header__search-key ml-auto rounded-md px-2 text-xs site-soft site-input">/</span>
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user