방식 개편
This commit is contained in:
@@ -17,8 +17,8 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 2 - 2 - 1 그리드 정렬 레이아웃 -->
|
||||
<div class="subject-grid-221">
|
||||
<!-- 가로 1열 5칸 캐러셀 레이아웃 -->
|
||||
<div class="subject-grid-carousel">
|
||||
<div
|
||||
v-for="(item, idx) in subjectList"
|
||||
:key="item.name"
|
||||
@@ -26,17 +26,18 @@
|
||||
:class="`card-item-${idx + 1}`"
|
||||
@click="openModal(item)"
|
||||
>
|
||||
<div class="card-inner">
|
||||
<figure class="card-inner m-0">
|
||||
<div class="img-wrap">
|
||||
<img
|
||||
:src="item.image"
|
||||
:alt="`${item.name} 1:1 맞춤 지도`"
|
||||
width="600"
|
||||
height="600"
|
||||
:src="item.path"
|
||||
:alt="`${shortSido || defaultSido} ${gradeShort || computedGradeShort} ${item.keyName} 과외 · ${regionDong || defaultDong} ${item.name}`"
|
||||
width="1080"
|
||||
height="1080"
|
||||
decoding="async"
|
||||
loading="eager"
|
||||
fetchpriority="high"
|
||||
class="subject-img"
|
||||
loading="lazy"
|
||||
/>
|
||||
<span class="subject-tag">{{ item.tag }}</span>
|
||||
<div class="zoom-overlay">
|
||||
<span class="zoom-btn">
|
||||
<i class="fa-solid fa-magnifying-glass-plus"></i>
|
||||
@@ -45,18 +46,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-info">
|
||||
<figcaption class="card-info">
|
||||
<div class="card-subject-name">
|
||||
<span class="sub-name">{{ item.name }}</span>
|
||||
<h3 class="sub-name m-0 text-inherit font-extrabold">{{ shortSido || defaultSido }} {{ gradeShort || computedGradeShort }} {{ item.name }}</h3>
|
||||
<span class="sub-grade">{{ grade }}</span>
|
||||
</div>
|
||||
<p class="card-subject-desc">{{ item.desc }}</p>
|
||||
<div class="card-action">
|
||||
<NuxtLink :to="getSubjectPageUrl(item.subjectKey)" class="card-action" @click.stop>
|
||||
<span>자세히 보기 & 신청</span>
|
||||
<i class="fa-solid fa-arrow-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -87,21 +88,21 @@
|
||||
<!-- 모달 좌측: 고해상도 생성 이미지 원본 -->
|
||||
<div class="modal-img-col">
|
||||
<img
|
||||
:src="selectedItem.image"
|
||||
:alt="`${selectedItem.name} 1:1 맞춤 과외`"
|
||||
width="600"
|
||||
height="600"
|
||||
:src="selectedItem.path"
|
||||
:alt="`${shortSido || defaultSido} ${gradeShort || computedGradeShort} ${selectedItem.keyName} 과외 · ${regionDong || defaultDong} ${selectedItem.name}`"
|
||||
width="1080"
|
||||
height="1080"
|
||||
decoding="async"
|
||||
class="modal-main-img"
|
||||
/>
|
||||
<span class="modal-img-badge">{{ selectedItem.tag }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 모달 우측: 상세 설명 및 액션 버튼 -->
|
||||
<div class="modal-content-col">
|
||||
<div class="modal-header">
|
||||
<span class="modal-pill">{{ regionDong || '관내' }} 1:1 밀착 코칭</span>
|
||||
<span class="modal-pill">{{ regionDong || defaultDong }} 1:1 밀착 코칭</span>
|
||||
<h3 class="modal-title">
|
||||
{{ selectedItem.name }}
|
||||
{{ shortSido || defaultSido }} {{ gradeShort || computedGradeShort }} {{ selectedItem.name }}
|
||||
<span class="text-sub">1:1 맞춤 마스터 클래스</span>
|
||||
</h3>
|
||||
<p class="modal-slogan">{{ selectedItem.slogan }}</p>
|
||||
@@ -148,7 +149,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const props = defineProps({
|
||||
@@ -158,7 +159,15 @@ const props = defineProps({
|
||||
},
|
||||
grade: {
|
||||
type: String,
|
||||
default: '중·고등'
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: '중등'
|
||||
},
|
||||
shortSido: {
|
||||
type: String,
|
||||
default: '대구'
|
||||
},
|
||||
currentSubject: {
|
||||
type: String,
|
||||
@@ -169,16 +178,22 @@ const props = defineProps({
|
||||
const router = useRouter()
|
||||
|
||||
const config = useRuntimeConfig()
|
||||
const siteDomain = config.public?.siteDomain || 'https://aeseo.cloud'
|
||||
const siteDomain = config.public?.siteDomain || 'https://soohyun.store'
|
||||
const defaultDong = '범어동'
|
||||
const defaultSido = '대구'
|
||||
|
||||
// 5대 핵심 과목 (2 2 1 순서 배치)
|
||||
const computedGradeShort = computed(() => {
|
||||
return props.grade === '초등학생' ? '초등' : props.grade === '고등학생' ? '고등' : '중등'
|
||||
})
|
||||
|
||||
// 5대 핵심 과목 (가로 1열 5칸 캐러셀 배치)
|
||||
const subjectList = [
|
||||
// 1행: 수학, 영어
|
||||
{
|
||||
name: '수학과외',
|
||||
keyName: '수학',
|
||||
subjectKey: 'math',
|
||||
tag: '인기 1위',
|
||||
image: `${siteDomain}/img/math-tutoring.png`,
|
||||
image: '/img/math-tutoring.png',
|
||||
path: '/img/math-tutoring.png',
|
||||
desc: '개념 구멍 추적 및 킬러 문항 1:1 완파',
|
||||
slogan: '단순 공식 암기가 아닌 원리 이해와 킬러 문항 해결력을 기릅니다.',
|
||||
@@ -190,9 +205,10 @@ const subjectList = [
|
||||
},
|
||||
{
|
||||
name: '영어과외',
|
||||
keyName: '영어',
|
||||
subjectKey: 'english',
|
||||
tag: '내신 필수',
|
||||
image: `${siteDomain}/img/english-tutoring.png`,
|
||||
image: '/img/english-tutoring.png',
|
||||
path: '/img/english-tutoring.png',
|
||||
desc: '교과서·부교재 전 지문 변형 및 서술형 영작',
|
||||
slogan: '어휘, 문법, 서술형 감점 0점화로 내신 1등급을 완성합니다.',
|
||||
@@ -202,12 +218,12 @@ const subjectList = [
|
||||
{ title: '1:1 구문 독해 & 빈칸 추론 특훈', desc: '문장 구조 분석을 통해 킬러 빈칸·순서 배열 문제를 빠르고 정확히 풉니다.' }
|
||||
]
|
||||
},
|
||||
// 2행: 국어, 과학
|
||||
{
|
||||
name: '국어과외',
|
||||
keyName: '국어',
|
||||
subjectKey: 'korean',
|
||||
tag: '문해력 완성',
|
||||
image: `${siteDomain}/img/korean-tutoring.png`,
|
||||
image: '/img/korean-tutoring.png',
|
||||
path: '/img/korean-tutoring.png',
|
||||
desc: '비문학 독해 논리와 교과서 문학 1:1 정밀 분석',
|
||||
slogan: '긴 지문도 흔들리지 않는 문해력과 서술형 채점 기준을 공략합니다.',
|
||||
@@ -219,9 +235,10 @@ const subjectList = [
|
||||
},
|
||||
{
|
||||
name: '과학과외',
|
||||
keyName: '과학',
|
||||
subjectKey: 'science',
|
||||
tag: '통합과학',
|
||||
image: `${siteDomain}/img/science-tutoring.png`,
|
||||
image: '/img/science-tutoring.png',
|
||||
path: '/img/science-tutoring.png',
|
||||
desc: '통합과학 원리 이해 및 물화생지 킬러 단원 정복',
|
||||
slogan: '까다로운 계산과 복잡한 개념을 1:1 시각화와 원리 풀이로 해결합니다.',
|
||||
@@ -231,12 +248,12 @@ const subjectList = [
|
||||
{ title: '수행평가 실험 보고서 1:1 가이드', desc: '지필고사뿐 아니라 감점되기 쉬운 과학 탐구 보고서 만점을 케어합니다.' }
|
||||
]
|
||||
},
|
||||
// 3행: 사회 (1개 단독 센터 정렬)
|
||||
{
|
||||
name: '사회과외',
|
||||
keyName: '사회',
|
||||
subjectKey: 'social',
|
||||
tag: '통합사회',
|
||||
image: `${siteDomain}/img/social-studies-tutoring.png`,
|
||||
image: '/img/social-studies-tutoring.png',
|
||||
path: '/img/social-studies-tutoring.png',
|
||||
desc: '통합사회·한국사 핵심 흐름 및 사탐 만점 전략',
|
||||
slogan: '무작정 외우지 않고 역사와 사회 현상의 맥락을 이해하며 1등급을 쟁취합니다.',
|
||||
@@ -271,11 +288,9 @@ const applyWithSubject = (subjectName) => {
|
||||
const cleanSubj = subjectName.replace(/과외$/, '').trim()
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
// 1. 커스텀 이벤트 발송 (Vue 반응형 formData.subject 즉시 업데이트)
|
||||
window.dispatchEvent(new CustomEvent('select-subject', { detail: { subject: cleanSubj } }))
|
||||
|
||||
setTimeout(() => {
|
||||
// 2. 칩 버튼 DOM 직접 클릭 트리거 (완벽 호환)
|
||||
const buttons = document.querySelectorAll('#leadFormSection button')
|
||||
for (const btn of buttons) {
|
||||
const text = btn.innerText.trim()
|
||||
@@ -286,14 +301,12 @@ const applyWithSubject = (subjectName) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 3. input/select fallback
|
||||
const subjSelect = document.getElementById('weakSubject') || document.getElementById('c-subject')
|
||||
if (subjSelect) {
|
||||
subjSelect.value = cleanSubj
|
||||
subjSelect.dispatchEvent(new Event('change'))
|
||||
}
|
||||
|
||||
// 4. 상단 폼 위치로 부드럽게 스크롤 이동
|
||||
const formTarget = document.getElementById('leadFormSection') || document.getElementById('consult-section')
|
||||
if (formTarget) {
|
||||
formTarget.scrollIntoView({ behavior: 'smooth' })
|
||||
@@ -304,8 +317,9 @@ const applyWithSubject = (subjectName) => {
|
||||
|
||||
// 해당 과목 전용 페이지 URL 생성 (NuxtLink 바인딩용)
|
||||
const getSubjectPageUrl = (subjectKey) => {
|
||||
const dong = props.regionDong || '서울'
|
||||
const grade = props.grade || '중학생'
|
||||
const dong = props.regionDong || defaultDong
|
||||
const validGrades = ['초등학생', '중학생', '고등학생']
|
||||
const grade = validGrades.includes(props.grade) ? props.grade : '중학생'
|
||||
const subMap = {
|
||||
math: '수학',
|
||||
english: '영어',
|
||||
@@ -317,13 +331,11 @@ const getSubjectPageUrl = (subjectKey) => {
|
||||
return `/${encodeURIComponent(dong)}/${encodeURIComponent(grade)}/${encodeURIComponent(subName)}`
|
||||
}
|
||||
|
||||
// 해당 과목 전용 페이지로 이동
|
||||
const goToSubjectPage = (subjectKey) => {
|
||||
closeModal()
|
||||
router.push(getSubjectPageUrl(subjectKey))
|
||||
}
|
||||
|
||||
// ESC 키로 모달 닫기
|
||||
const handleKeyDown = (e) => {
|
||||
if (e.key === 'Escape' && selectedItem.value) {
|
||||
closeModal()
|
||||
@@ -347,7 +359,7 @@ onUnmounted(() => {
|
||||
<style scoped>
|
||||
.subject-gallery-section {
|
||||
width: 100%;
|
||||
max-width: 1080px;
|
||||
max-width: 1120px;
|
||||
margin: 40px auto 60px;
|
||||
padding: 0 16px;
|
||||
position: relative;
|
||||
@@ -358,13 +370,13 @@ onUnmounted(() => {
|
||||
background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%);
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 28px;
|
||||
padding: clamp(24px, 4vw, 44px) clamp(16px, 3vw, 36px);
|
||||
padding: clamp(24px, 4vw, 40px) clamp(16px, 3vw, 28px);
|
||||
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.05);
|
||||
}
|
||||
|
||||
.gallery-header {
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
.gallery-badge {
|
||||
@@ -398,31 +410,23 @@ onUnmounted(() => {
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
/* 2 - 2 - 1 그리드 레이아웃 */
|
||||
.subject-grid-221 {
|
||||
/* 가로 1열 5칸 캐러셀 그리드 레이아웃 */
|
||||
.subject-grid-carousel {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20px;
|
||||
grid-template-columns: repeat(5, minmax(180px, 1fr));
|
||||
gap: 14px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 5번째 아이템: 3행 단독 1개 (2열 span 및 중앙 정렬) */
|
||||
.card-item-5 {
|
||||
grid-column: 1 / -1;
|
||||
justify-self: center;
|
||||
width: 100%;
|
||||
max-width: calc(50% - 10px);
|
||||
}
|
||||
|
||||
.gallery-card {
|
||||
cursor: pointer;
|
||||
border-radius: 20px;
|
||||
border-radius: 18px;
|
||||
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
}
|
||||
|
||||
.card-inner {
|
||||
background: #ffffff;
|
||||
border-radius: 20px;
|
||||
border-radius: 18px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #e2e8f0;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
|
||||
@@ -444,6 +448,7 @@ onUnmounted(() => {
|
||||
aspect-ratio: 1 / 1;
|
||||
overflow: hidden;
|
||||
background: #f1f5f9;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.subject-img {
|
||||
@@ -457,20 +462,6 @@ onUnmounted(() => {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.subject-tag {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
left: 14px;
|
||||
background: rgba(15, 23, 42, 0.85);
|
||||
backdrop-filter: blur(4px);
|
||||
color: #ffffff;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 800;
|
||||
padding: 4px 12px;
|
||||
border-radius: 9999px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.zoom-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
@@ -490,9 +481,9 @@ onUnmounted(() => {
|
||||
.zoom-btn {
|
||||
background: #ffffff;
|
||||
color: #0f172a;
|
||||
font-size: 0.88rem;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 800;
|
||||
padding: 10px 18px;
|
||||
padding: 8px 14px;
|
||||
border-radius: 9999px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -507,7 +498,7 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.card-info {
|
||||
padding: 18px 20px;
|
||||
padding: 14px 14px 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
@@ -516,59 +507,67 @@ onUnmounted(() => {
|
||||
.card-subject-name {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 8px;
|
||||
justify-content: space-between;
|
||||
gap: 6px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.sub-name {
|
||||
font-size: 1.2rem;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 800;
|
||||
color: #0f172a;
|
||||
margin: 0;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.sub-grade {
|
||||
font-size: 0.78rem;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
color: #64748b;
|
||||
background: #f1f5f9;
|
||||
padding: 2px 8px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 6px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.card-subject-desc {
|
||||
font-size: 0.85rem;
|
||||
font-size: 0.78rem;
|
||||
color: #475569;
|
||||
line-height: 1.45;
|
||||
margin-bottom: 14px;
|
||||
margin-bottom: 12px;
|
||||
flex: 1;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.card-action {
|
||||
font-size: 0.82rem;
|
||||
font-size: 0.76rem;
|
||||
font-weight: 700;
|
||||
color: var(--primary-color, #1e3a8a);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
gap: 5px;
|
||||
transition: gap 0.2s ease;
|
||||
}
|
||||
|
||||
.gallery-card:hover .card-action {
|
||||
gap: 10px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* 모바일 반응형 대응 */
|
||||
@media (max-width: 640px) {
|
||||
.subject-grid-221 {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
/* 태블릿/모바일 가로 스크롤 캐러셀 반응형 대응 */
|
||||
@media (max-width: 1024px) {
|
||||
.subject-grid-carousel {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x mandatory;
|
||||
gap: 12px;
|
||||
padding-bottom: 12px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.card-item-5 {
|
||||
grid-column: auto;
|
||||
max-width: 100%;
|
||||
justify-self: stretch;
|
||||
|
||||
.gallery-card {
|
||||
flex: 0 0 220px;
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,19 +648,6 @@ onUnmounted(() => {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.modal-img-badge {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 16px;
|
||||
background: var(--accent-color, #d97706);
|
||||
color: #ffffff;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 800;
|
||||
padding: 5px 12px;
|
||||
border-radius: 9999px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.modal-content-col {
|
||||
padding: clamp(24px, 4vw, 36px);
|
||||
display: flex;
|
||||
@@ -809,11 +795,11 @@ onUnmounted(() => {
|
||||
|
||||
.modal-fade-enter-active .modal-card,
|
||||
.modal-fade-leave-active .modal-card {
|
||||
transition: transform 0.3s cubic-bezier(0.25, 1, 0.5, 1);
|
||||
transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
}
|
||||
|
||||
.modal-fade-enter-from .modal-card,
|
||||
.modal-fade-leave-to .modal-card {
|
||||
transform: scale(0.92) translateY(20px);
|
||||
transform: scale(0.95) translateY(10px);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user