방식 개편
@@ -2,38 +2,33 @@
|
||||
<section class="faq-section">
|
||||
<div class="section-header">
|
||||
<span class="section-badge">궁금한 점을 풀어드립니다</span>
|
||||
<h2 class="section-title">{{ regionDong }} 1:1 과외 자주 묻는 질문</h2>
|
||||
<h2 class="section-title">{{ shortSido }} {{ gradeShort }} {{ subjectName }} 과외 · {{ regionDong }} 1:1 과외 자주 묻는 질문</h2>
|
||||
<p class="section-desc">학부모님들께서 가장 많이 문의하시는 내용을 모았습니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="faq-list">
|
||||
<div
|
||||
<details
|
||||
v-for="(faq, idx) in faqs"
|
||||
:key="idx"
|
||||
class="faq-item"
|
||||
:class="{ active: openIndex === idx }"
|
||||
class="faq-item qa"
|
||||
:open="idx === 0"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="faq-question"
|
||||
@click="toggle(idx)"
|
||||
:aria-expanded="openIndex === idx"
|
||||
>
|
||||
<summary class="faq-question">
|
||||
<span class="q-icon">Q</span>
|
||||
<span class="q-text">{{ faq.q }}</span>
|
||||
<span class="toggle-icon">{{ openIndex === idx ? '▲' : '▼' }}</span>
|
||||
</button>
|
||||
<div v-show="openIndex === idx" class="faq-answer">
|
||||
<span class="toggle-icon">▼</span>
|
||||
</summary>
|
||||
<div class="faq-answer ans">
|
||||
<span class="a-icon">A</span>
|
||||
<p class="a-text">{{ faq.a }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
regionDong: {
|
||||
@@ -44,38 +39,40 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: '중등'
|
||||
},
|
||||
shortSido: {
|
||||
type: String,
|
||||
default: '부산'
|
||||
},
|
||||
subjectName: {
|
||||
type: String,
|
||||
default: '영어'
|
||||
default: '수학'
|
||||
}
|
||||
})
|
||||
|
||||
const openIndex = ref(0)
|
||||
|
||||
const toggle = (idx) => {
|
||||
openIndex.value = openIndex.value === idx ? -1 : idx
|
||||
}
|
||||
|
||||
const faqs = computed(() => [
|
||||
{
|
||||
q: `${props.regionDong} ${props.grade} ${props.subjectName} 방문 과외와 온라인 화상 과외 중 어떤 것이 가능한가요?`,
|
||||
a: `학생과 학부모님의 선호에 따라 100% 자택 방문 대면 과외 또는 실시간 쌍방향 비대면 화상 과외 중 자유롭게 선택하실 수 있습니다. ${props.regionDong} 전 지역 방문 수업이 가능합니다.`
|
||||
q: `${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외 및 ${props.regionDong} ${props.grade} ${props.subjectName} 방문 과외와 화상 과외 중 어떤 것이 가능한가요?`,
|
||||
a: `학생과 학부모님의 선호에 따라 ${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외 100% 자택 방문 대면 수업 또는 실시간 쌍방향 화상 과외 중 자유롭게 선택하실 수 있습니다. ${props.regionDong} 전 지역 방문 수업이 가능합니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.grade} ${props.subjectName} 전문 선생님이 학생과 잘 맞지 않으면 교체 가능한가요?`,
|
||||
a: '네, 1회 무료 모의수업을 통해 사전에 호흡을 맞추며, 정규 수업 시작 후에도 학생의 성향이나 요청에 따라 추가 비용 없이 100% 무료 교체 및 환불 규정을 보장합니다.'
|
||||
q: `${props.shortSido} ${props.gradeShort} 과외 · ${props.regionDong} ${props.grade} ${props.subjectName} 전문 선생님이 학생과 맞지 않으면 교체 가능한가요?`,
|
||||
a: `네, ${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외는 1회 무료 모의수업을 통해 사전에 호흡을 맞추며, 정규 수업 시작 후에도 학생의 성향이나 요청에 따라 추가 비용 없이 100% 무료 교체 및 환불 규정을 보장합니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.grade} ${props.subjectName} 과외 수업 비용은 어떻게 되나요?`,
|
||||
a: `${props.grade} 내신 단계, 주당 수업 횟수, 수업 시간(1회 60분/90분/120분)에 따라 표준 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다. 무료 상담 시 상세 견적표를 안내해 드립니다.`
|
||||
q: `${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외 및 ${props.regionDong} ${props.grade} ${props.subjectName} 과외 수업 비용은 어떻게 되나요?`,
|
||||
a: `${props.shortSido} ${props.gradeShort} 과외는 ${props.grade} 내신 단계, 주당 수업 횟수, 수업 시간(1회 60분/90분/120분)에 따라 표준 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다. 무료 상담 시 상세 견적표를 안내해 드립니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.regionDong} 학교 중간·기말고사 직전 단기 ${props.subjectName} 족보 클리닉도 가능한가요?`,
|
||||
a: `네, 시험 3~4주 전 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${props.grade} ${props.subjectName} 단기 속성 킬러 클리닉 프로그램도 상시 운영 중입니다.`
|
||||
q: `${props.regionDong} 학교 중간·기말고사 직전 단기 ${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외 족보 클리닉도 가능한가요?`,
|
||||
a: `네, 시험 3~4주 전 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${props.regionDong} ${props.grade} ${props.subjectName} 과외 단기 속성 킬러 클리닉 프로그램도 상시 운영 중입니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.subjectName} 외에 다른 과목도 함께 상담받을 수 있나요?`,
|
||||
a: `${props.subjectName} 집중 신청은 물론, 국영수 또는 수탐 복합 패키지로 맞춤 구성하여 전 과목 플래너 관리와 함께 시간표를 편성하실 수 있습니다.`
|
||||
q: `${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외 외에 다른 과목도 함께 상담받을 수 있나요?`,
|
||||
a: `${props.subjectName} 집중 신청은 물론, 국영수 또는 수탐 복합 ${props.shortSido} ${props.gradeShort} 과외 패키지로 맞춤 구성하여 전 과목 플래너 관리와 함께 시간표를 편성하실 수 있습니다.`
|
||||
}
|
||||
])
|
||||
</script>
|
||||
@@ -146,6 +143,11 @@ const faqs = computed(() => [
|
||||
font-size: clamp(0.9rem, 2.2vw, 1.02rem);
|
||||
font-weight: 800;
|
||||
color: var(--text-color, #0f172a);
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.faq-question::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.q-icon {
|
||||
@@ -172,6 +174,11 @@ const faqs = computed(() => [
|
||||
font-size: 0.8rem;
|
||||
color: #94a3b8;
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
details[open] .toggle-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.faq-answer {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="focus-header">
|
||||
<span class="focus-badge">{{ isElementary ? '초등 맞춤 집중 케어' : `${displayGrade} 실전 시험 케어` }}</span>
|
||||
<h2 class="focus-main-title">
|
||||
{{ regionDong }} {{ displayGrade }} {{ displaySubject }}과외
|
||||
{{ shortSido ? `${shortSido} ` : '' }}{{ regionDong }} {{ displayGrade }} {{ displaySubject }}과외
|
||||
<span class="text-accent">5대 핵심 솔루션</span>
|
||||
</h2>
|
||||
<p class="focus-sub-desc">
|
||||
@@ -12,7 +12,7 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 네이버 5개 멀티 썸네일 스니펫 및 상담 링크 매칭용 5개 리스트 -->
|
||||
<!-- 네이버 5개 멀티 썸네일 스니펫 및 상담 링크 매칭용 가로 5열 캐러셀 -->
|
||||
<div class="focus-grid">
|
||||
<a
|
||||
v-for="(item, idx) in programList"
|
||||
@@ -21,27 +21,30 @@
|
||||
class="focus-card"
|
||||
:title="`${item.title} 상담 신청`"
|
||||
>
|
||||
<div class="focus-thumb-wrap">
|
||||
<img
|
||||
:src="item.image"
|
||||
:alt="`${item.title} 1:1 맞춤 지도`"
|
||||
width="500"
|
||||
height="500"
|
||||
loading="lazy"
|
||||
class="focus-img"
|
||||
/>
|
||||
<span class="step-tag">STEP 0{{ idx + 1 }}</span>
|
||||
</div>
|
||||
|
||||
<div class="focus-info">
|
||||
<div class="focus-item-tag">{{ item.tag }}</div>
|
||||
<strong class="focus-item-title">{{ item.title }}</strong>
|
||||
<p class="focus-item-desc">{{ item.desc }}</p>
|
||||
<div class="focus-cta-link">
|
||||
<span>1:1 상담 예약</span>
|
||||
<span class="arrow-sym">→</span>
|
||||
<figure class="focus-figure m-0 flex flex-col flex-1">
|
||||
<div class="focus-thumb-wrap">
|
||||
<img
|
||||
:src="item.image"
|
||||
:alt="item.title"
|
||||
width="1080"
|
||||
height="1080"
|
||||
decoding="async"
|
||||
loading="eager"
|
||||
fetchpriority="high"
|
||||
class="focus-img"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<figcaption class="focus-info">
|
||||
<div class="focus-item-tag">{{ item.tag }}</div>
|
||||
<h3 class="focus-item-title m-0">{{ item.title }}</h3>
|
||||
<p class="focus-item-desc">{{ item.desc }}</p>
|
||||
<div class="focus-cta-link">
|
||||
<span>1:1 상담 예약</span>
|
||||
<span class="arrow-sym">→</span>
|
||||
</div>
|
||||
</figcaption>
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -56,6 +59,14 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: '중등'
|
||||
},
|
||||
shortSido: {
|
||||
type: String,
|
||||
default: '부산'
|
||||
},
|
||||
subjectName: {
|
||||
type: String,
|
||||
default: '수학'
|
||||
@@ -78,7 +89,7 @@ const displaySubject = computed(() => {
|
||||
return props.subjectName || '수학'
|
||||
})
|
||||
|
||||
// 초등 vs 중등/고등 5개 항목 분기
|
||||
// 초등 vs 중등/고등 5개 항목 분기 (네이버 썸네일 추출 가능한 고해상도 실사 .png 5종 적용)
|
||||
const programList = computed(() => {
|
||||
const dong = props.regionDong ? `${props.regionDong} ` : ''
|
||||
const sub = displaySubject.value
|
||||
@@ -90,31 +101,31 @@ const programList = computed(() => {
|
||||
tag: '개념 완성',
|
||||
title: `${dong}초등 ${sub}과외 - 기초학습`,
|
||||
desc: '개념 쏙쏙 이해와 튼튼한 연산 기본기 완성',
|
||||
image: '/images/focus/elem-1-basic.svg'
|
||||
image: '/img/math-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '학습 코칭',
|
||||
title: `${dong}초등 ${sub}과외 - 공부방법`,
|
||||
desc: '스스로 원리를 깨우치는 올바른 문제 해결력',
|
||||
image: '/images/focus/elem-2-method.svg'
|
||||
image: '/img/english-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '밀착 피드백',
|
||||
title: `${dong}초등 ${sub}과외 - 숙제검사`,
|
||||
desc: '매일 1:1 오답 점검과 꼼꼼한 피드백 클리닉',
|
||||
image: '/images/focus/elem-3-homework.svg'
|
||||
image: '/img/korean-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '자기주도',
|
||||
title: `${dong}초등 ${sub}과외 - 공부습관`,
|
||||
desc: '매일 스스로 책상에 앉는 주도적 학습 루틴',
|
||||
image: '/images/focus/elem-4-habit.svg'
|
||||
image: '/img/science-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '상위권 도약',
|
||||
title: `${dong}초등 ${sub}과외 - 중등대비`,
|
||||
desc: '중학교 내신 서술형과 심화 개념 선행 마스터',
|
||||
image: '/images/focus/elem-5-middleprep.svg'
|
||||
image: '/img/social-studies-tutoring.png'
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -125,31 +136,31 @@ const programList = computed(() => {
|
||||
tag: '기출 정복',
|
||||
title: `${dong}${grd} 중간고사 ${sub}과외`,
|
||||
desc: '학교별 기출 족보 완벽 분석 및 서술형 킬러 대비',
|
||||
image: '/images/focus/sec-1-midterm.svg'
|
||||
image: '/img/math-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '학기말 총력',
|
||||
title: `${dong}${grd} 기말고사 ${sub}과외`,
|
||||
desc: '전 범위 오답 분석 및 취약 유형 완벽 클리닉',
|
||||
image: '/images/focus/sec-2-final.svg'
|
||||
image: '/img/english-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '수능·전국연합',
|
||||
title: `${dong}${grd} 모의고사 ${sub}과외`,
|
||||
desc: '수능형 사고력 확장 및 실전 시간 배분 특훈',
|
||||
image: '/images/focus/sec-3-mock.svg'
|
||||
image: '/img/korean-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '내신 만점',
|
||||
title: `${dong}${grd} 수행평가 ${sub}과외`,
|
||||
desc: '조건 감점 0점화 및 과제·보고서 완벽 케어',
|
||||
image: '/images/focus/sec-4-assessment.svg'
|
||||
image: '/img/science-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '1등급 집중',
|
||||
title: `${dong}${grd} 내신대비 ${sub}과외`,
|
||||
desc: '관내 교과서·부교재 적중 1:1 맞춤 지도',
|
||||
image: '/images/focus/sec-5-schoolprep.svg'
|
||||
image: '/img/social-studies-tutoring.png'
|
||||
}
|
||||
]
|
||||
})
|
||||
@@ -202,10 +213,10 @@ const programList = computed(() => {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 5열 카드 그리드 */
|
||||
/* 가로 1열 5칸 캐러셀 그리드 */
|
||||
.focus-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
grid-template-columns: repeat(5, minmax(180px, 1fr));
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
@@ -234,6 +245,7 @@ const programList = computed(() => {
|
||||
aspect-ratio: 1 / 1;
|
||||
background: #f1f5f9;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.focus-img {
|
||||
@@ -248,20 +260,6 @@ const programList = computed(() => {
|
||||
transform: scale(1.04);
|
||||
}
|
||||
|
||||
.step-tag {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
padding: 2px 8px;
|
||||
background: rgba(0, 0, 0, 0.55);
|
||||
backdrop-filter: blur(4px);
|
||||
color: #ffffff;
|
||||
font-size: 0.68rem;
|
||||
font-weight: 800;
|
||||
border-radius: 4px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.focus-info {
|
||||
padding: 14px 12px;
|
||||
display: flex;
|
||||
@@ -281,7 +279,7 @@ const programList = computed(() => {
|
||||
font-weight: 800;
|
||||
color: #0f172a;
|
||||
line-height: 1.35;
|
||||
margin-bottom: 6px;
|
||||
margin: 0 0 6px 0;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
@@ -313,52 +311,37 @@ const programList = computed(() => {
|
||||
transform: translateX(3px);
|
||||
}
|
||||
|
||||
/* 태블릿 및 모바일 반응형 */
|
||||
@media (max-width: 960px) {
|
||||
/* 태블릿 및 모바일 가로 스크롤 캐러셀 반응형 */
|
||||
@media (max-width: 1024px) {
|
||||
.focus-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.focus-grid {
|
||||
grid-template-columns: 1fr;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x mandatory;
|
||||
gap: 12px;
|
||||
padding-bottom: 12px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.focus-card {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex: 0 0 210px;
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.focus-grid {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x mandatory;
|
||||
gap: 12px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.focus-thumb-wrap {
|
||||
width: 105px;
|
||||
height: 105px;
|
||||
aspect-ratio: 1 / 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.focus-info {
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.focus-item-title {
|
||||
font-size: 0.88rem;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.focus-item-desc {
|
||||
font-size: 0.74rem;
|
||||
margin-bottom: 6px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.focus-cta-link {
|
||||
padding-top: 4px;
|
||||
font-size: 0.72rem;
|
||||
.focus-card {
|
||||
flex: 0 0 200px;
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<header class="hero-banner-clean bg-white border-b border-slate-200/80 pt-10 sm:pt-14 pb-14 sm:pb-18 px-4 sm:px-6 relative overflow-hidden text-center">
|
||||
<section class="hero-banner hero-banner-clean bg-white border-b border-slate-200/80 pt-10 sm:pt-14 pb-14 sm:pb-18 px-4 sm:px-6 relative overflow-hidden text-center" itemscope itemtype="https://schema.org/Course">
|
||||
|
||||
<!-- 은은한 상단 엠비언트 라이트 -->
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-blue-50/40 via-transparent to-transparent pointer-events-none"></div>
|
||||
@@ -12,16 +12,23 @@
|
||||
<span>{{ region.dong }} 학군 전담 | 서울대·연고대 및 베테랑 강사진 100% 신원 보증</span>
|
||||
</div>
|
||||
|
||||
<!-- SEO 메인 H1 (사용자 지정 롱테일 조합형: [지역] + [학년] + [과목]과외 + 검증된 전문 선생님 100% 매칭) -->
|
||||
<h1 class="text-2xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.22] sm:leading-[1.18] mb-4">
|
||||
<span>{{ displayRegionName }} {{ grade }} {{ subjectName }}과외</span><br />
|
||||
<span class="text-blue-600">우리 아이 맞춤 검증된 전문 선생님 100% 매칭</span>
|
||||
<!-- 1. H1 -->
|
||||
<h1 itemprop="headline" class="text-2xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.22] sm:leading-[1.18] mb-3">
|
||||
<span class="highlight text-blue-600">{{ shortSidoName }} {{ gradeShortName }} {{ subjectName }} 과외 · {{ region.dong }} {{ grade }} {{ subjectName }}과외</span><br />
|
||||
1:1 맞춤 학습으로 성적 역전!
|
||||
</h1>
|
||||
|
||||
<!-- 서브 카피 (비용 시세 비교 + 학교 기출 분석 + 무료 시범수업 신뢰 트리거) -->
|
||||
<p class="text-xs sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-7">
|
||||
{{ region.dong }} 인근 학교별 기출 분석부터 과외 비용·시세 비교, 취약 개념 클리닉까지.<br class="hidden sm:inline" />
|
||||
직접 수업받아보고 결정하는 <strong>1:1 무료 방문·화상 시범수업</strong>을 신청하세요.
|
||||
<!-- 2. meta (H1 바로 다음 줄) -->
|
||||
<meta itemprop="name" :content="`${shortSidoName} ${gradeShortName} ${subjectName} 과외 · ${shortSidoName} ${gradeShortName} 과외 (${region.dong})`" />
|
||||
<meta itemprop="description" :content="`${shortSidoName} ${gradeShortName} ${subjectName} 과외 및 ${shortSidoName} ${gradeShortName} 과외 전문 매칭. ${displayRegionName} ${grade} ${subjectName} 1:1 방문·화상 맞춤 수업`" />
|
||||
<meta itemprop="keywords" :content="`${shortSidoName} ${gradeShortName} ${subjectName} 과외, ${shortSidoName} ${gradeShortName} 과외, ${region.dong} ${gradeShortName} ${subjectName} 과외, ${region.dong} ${gradeShortName} 과외, ${displayRegionName} ${grade} ${subjectName}과외`" />
|
||||
<meta itemprop="image" content="/img/math-tutoring.png" />
|
||||
<!-- 3. H2 (meta 바로 다음 줄) -->
|
||||
<h2 class="hero-subtitle">
|
||||
{{ shortSidoName }} {{ gradeShortName }} 과외 · {{ displayRegionName }} {{ gradeShortName }} {{ subjectName }} 과외 검증된 전문 선생님 1:1 매칭
|
||||
</h2>
|
||||
<!-- 4. 일반글 p (H2 바로 다음 줄) -->
|
||||
<p class="sub-headline text-xs sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-7">
|
||||
{{ shortSidoName }} {{ gradeShortName }} {{ subjectName }} 과외 및 {{ shortSidoName }} {{ gradeShortName }} 과외를 찾으시는 학부모님을 위해 {{ region.dong }} 인근 학교별 기출 족보 분석부터 개인별 취약 개념 완벽 보완, 투명한 과외비 안내와 무료 시범수업까지 1:1 밀착 커리큘럼을 제공합니다.
|
||||
</p>
|
||||
|
||||
<!-- 4대 핵심 신뢰 지표 바 -->
|
||||
@@ -84,15 +91,15 @@
|
||||
|
||||
<!-- 태그 목록 -->
|
||||
<div class="flex justify-center flex-wrap gap-1.5">
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ shortSidoName }}{{ gradeShortName }}{{ subjectName }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ shortSidoName }}{{ gradeShortName }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ region.dong }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ region.dong }}{{ subjectName }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ grade }}내신대비</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#과외비용시세</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#1대1무료시범수업</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</header>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -111,12 +118,24 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
subjectName: {
|
||||
type: String,
|
||||
default: '수학'
|
||||
}
|
||||
})
|
||||
|
||||
const shortSidoName = computed(() => {
|
||||
return (props.region?.sido || '').replace(/특별시|광역시|특별자치시|도/g, '').trim()
|
||||
})
|
||||
|
||||
const gradeShortName = computed(() => {
|
||||
return props.gradeShort || (props.grade === '초등학생' ? '초등' : props.grade === '고등학생' ? '고등' : '중등')
|
||||
})
|
||||
|
||||
const noticeIdx = ref(0)
|
||||
let timer = null
|
||||
|
||||
@@ -171,4 +190,12 @@ const displayRegionName = computed(() => {
|
||||
.hero-banner-clean {
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-size: 1.15rem;
|
||||
font-weight: 700;
|
||||
color: #334155;
|
||||
margin-bottom: 0.75rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -116,15 +116,15 @@ const nearbyDongs = computed(() => {
|
||||
}
|
||||
|
||||
// 만약 동일 구의 동이 부족하면 전체에서 다른 동 가져오기
|
||||
if (candidates.length < 5) {
|
||||
if (candidates.length < 12) {
|
||||
const others = allList
|
||||
.filter(r => r.dong !== curDong && !candidates.includes(r.dong))
|
||||
.map(r => r.dong)
|
||||
candidates = [...candidates, ...others]
|
||||
}
|
||||
|
||||
// 중복 제거 후 6개 반환
|
||||
return Array.from(new Set(candidates)).slice(0, 6)
|
||||
// 중복 제거 후 12개 반환
|
||||
return Array.from(new Set(candidates)).slice(0, 12)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -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.cloud'
|
||||
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>
|
||||
|
||||
@@ -3,30 +3,29 @@
|
||||
<!-- 1. 클린 미니멀 프리미엄 네비게이션 헤더 (기본 홈과 동일) -->
|
||||
<AppHeader :siteName="siteName" />
|
||||
|
||||
<!-- 2. 세련된 지역 센터 식별 서브 바 (모던 칩 배너) -->
|
||||
<div class="bg-blue-50/70 border-b border-blue-100/70 py-2.5 px-4">
|
||||
<!-- 2. 시맨틱 브레드크럼 네비게이션 바 (더세이브 nav.bc 구조 동기화) -->
|
||||
<nav class="bc bg-blue-50/70 border-b border-blue-100/70 py-2.5 px-4" aria-label="현재 위치">
|
||||
<div class="max-w-4xl mx-auto flex items-center justify-between flex-wrap gap-2 text-xs">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="inline-flex items-center gap-1 font-bold text-blue-700 bg-white px-2.5 py-0.5 rounded-full border border-blue-200/80 shadow-xs">
|
||||
<i class="fa-solid fa-location-dot text-blue-600 text-[10px]"></i>
|
||||
{{ parsed.shortRegionName }} 센터
|
||||
</span>
|
||||
<span class="text-slate-600 font-medium">
|
||||
{{ parsed.dong }} ({{ parsed.sigungu }}) 관내 초·중·고 1:1 맞춤 전담
|
||||
</span>
|
||||
<div class="flex items-center gap-1.5 text-slate-600 font-medium">
|
||||
<NuxtLink to="/" class="hover:text-blue-600 font-semibold transition-colors">홈</NuxtLink>
|
||||
<span class="text-slate-400">›</span>
|
||||
<span>{{ parsed.dong }} 과외</span>
|
||||
<span class="text-slate-400">›</span>
|
||||
<strong class="font-bold text-blue-700">{{ parsed.shortSido }} {{ parsed.gradeShort }} {{ parsed.subjectName }} 과외</strong>
|
||||
</div>
|
||||
<div class="hidden sm:flex items-center gap-1 text-slate-500 font-medium">
|
||||
<i class="fa-solid fa-shield-check text-emerald-600 text-xs"></i>
|
||||
<span>검증된 전문 선생님 100% 매칭</span>
|
||||
<span>{{ parsed.shortRegionName }} 센터 · 검증된 전문 선생님 100% 매칭</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- 3. 상단 히어로 배너 (H1 태그 포함) -->
|
||||
<!-- 3. 상단 히어로 배너 (H1 -> meta -> H2 -> p 순서) -->
|
||||
<HeroBanner
|
||||
:region="parsed.region"
|
||||
:shortRegionName="parsed.shortRegionName"
|
||||
:grade="parsed.grade"
|
||||
:grade-short="parsed.gradeShort"
|
||||
:subjectName="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -67,6 +66,8 @@
|
||||
<FaqAccordion
|
||||
:regionDong="parsed.dong"
|
||||
:grade="parsed.grade"
|
||||
:gradeShort="parsed.gradeShort"
|
||||
:shortSido="parsed.shortSido"
|
||||
:subjectName="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -74,6 +75,8 @@
|
||||
<FastConsultFocus
|
||||
:regionDong="parsed.dong"
|
||||
:grade="parsed.grade"
|
||||
:gradeShort="parsed.gradeShort"
|
||||
:shortSido="parsed.shortSido"
|
||||
:subjectName="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -81,6 +84,8 @@
|
||||
<SubjectCarousel
|
||||
:regionDong="parsed.dong"
|
||||
:grade="parsed.grade"
|
||||
:gradeShort="parsed.gradeShort"
|
||||
:shortSido="parsed.shortSido"
|
||||
:currentSubject="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -97,13 +102,11 @@
|
||||
:defaultGrade="parsed.grade"
|
||||
:defaultSubject="parsed.subjectName"
|
||||
/>
|
||||
|
||||
<!-- 14. 클린 사이트 푸터 -->
|
||||
<AppFooter />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { parseRouteSlug, getCurriculumBySubject, getAllSubjectsList, getPopularRegions } from '~/utils/dataHelper'
|
||||
import { generateSeoMeta } from '~/utils/seoHelper'
|
||||
@@ -112,28 +115,27 @@ const route = useRoute()
|
||||
const config = useRuntimeConfig()
|
||||
const siteName = config.public?.siteName || '공부짝꿍'
|
||||
|
||||
// URL 파라미터 파싱
|
||||
const slug = route.params.slug
|
||||
const parsed = parseRouteSlug(slug)
|
||||
// URL 파라미터 파싱 (반응형 computed)
|
||||
const parsed = computed(() => parseRouteSlug(route.params.slug))
|
||||
|
||||
// 커리큘럼 데이터 로드
|
||||
const curriculum = getCurriculumBySubject(parsed.subjectKey)
|
||||
const curriculum = computed(() => getCurriculumBySubject(parsed.value.subjectKey))
|
||||
const allSubjects = getAllSubjectsList()
|
||||
const popularRegions = getPopularRegions(12)
|
||||
|
||||
// 네이버 Yeti 봇 100% 대응 SEO 메타태그 설정
|
||||
const seo = generateSeoMeta(
|
||||
parsed,
|
||||
const seo = computed(() => generateSeoMeta(
|
||||
parsed.value,
|
||||
config.public.siteName,
|
||||
config.public.siteDomain
|
||||
)
|
||||
))
|
||||
|
||||
useHead({
|
||||
title: seo.title,
|
||||
meta: seo.meta,
|
||||
link: seo.link,
|
||||
script: seo.script
|
||||
})
|
||||
useHead(() => ({
|
||||
title: seo.value.title,
|
||||
meta: seo.value.meta,
|
||||
link: seo.value.link,
|
||||
script: seo.value.script
|
||||
}))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<!-- 1. Header (클린 미니멀 프리미엄 네비게이션) -->
|
||||
<header class="bg-white/95 backdrop-blur-md border-b border-slate-200/80 sticky top-0 z-40 w-full transition-all">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6 py-3.5 flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<NuxtLink to="/" class="flex items-center gap-3">
|
||||
<div class="w-9 h-9 rounded-xl bg-blue-600 flex items-center justify-center text-white font-extrabold text-base shadow-sm">
|
||||
G
|
||||
{{ siteName.charAt(0) }}
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-extrabold text-lg sm:text-xl tracking-tight text-slate-900">{{ siteName }}</span>
|
||||
@@ -14,7 +14,7 @@
|
||||
교육청 등록 협력
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<a href="tel:010-5961-5807" class="hidden sm:flex items-center gap-1.5 text-sm font-semibold text-slate-600 hover:text-blue-600 transition">
|
||||
@@ -32,8 +32,8 @@
|
||||
<!-- 2. Main Body -->
|
||||
<main class="w-full pb-20">
|
||||
|
||||
<!-- 히어로 섹션 (AI 스타일 형광/물결 제거, 정제된 모던 에듀테크 캔버스) -->
|
||||
<section class="w-full bg-white border-b border-slate-200/80 pt-12 sm:pt-16 pb-20 px-4 sm:px-6 text-center relative overflow-hidden">
|
||||
<!-- 히어로 섹션 (H1 -> meta -> H2 -> p 순서) -->
|
||||
<section class="hero-section w-full bg-white border-b border-slate-200/80 pt-12 sm:pt-16 pb-20 px-4 sm:px-6 text-center relative overflow-hidden" itemscope itemtype="https://schema.org/EducationalOrganization">
|
||||
|
||||
<!-- 은은한 상단 엠비언트 라이트 (절제된 디자이너 톤) -->
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-blue-50/40 via-transparent to-transparent pointer-events-none"></div>
|
||||
@@ -46,16 +46,22 @@
|
||||
<span>해운대·수영·동래 등 부산 전지역 전담 | 서울대·부산대 및 베테랑 강사진 100% 신원 보증</span>
|
||||
</div>
|
||||
|
||||
<!-- 메인 H1 (지역 기반 검색 상위 노출 30자 규격 및 학부모 고의도 롱테일 키워드) -->
|
||||
<h1 class="text-3xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.2] sm:leading-[1.18] mb-4">
|
||||
부산 초·중·고 1:1 맞춤 과외 매칭<br class="hidden sm:inline" />
|
||||
<span class="text-blue-600">검증된 전문 선생님 100% 매칭</span>
|
||||
<!-- 1. 메인 H1 -->
|
||||
<h1 class="text-3xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.2] sm:leading-[1.18] mb-3">
|
||||
부산 중등 수학 과외 · 초·중·고 1:1 맞춤 과외 매칭<br class="hidden sm:inline" />
|
||||
<span class="text-blue-600">내신·수능 성적 향상의 시작</span>
|
||||
</h1>
|
||||
|
||||
<!-- 서브 헤드라인 (비용 시세 비교 + 해운대 등 부산 학교 기출 분석 + 무료 시범수업) -->
|
||||
<p class="text-sm sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-8">
|
||||
과외 비용·시세 투명 비교부터 무료 시범수업 신청까지.<br class="hidden sm:inline" />
|
||||
해운대·수영·동래 등 부산 관내 학교별 기출 족보를 완벽 분석하여 <strong>내신 1등급 역전 솔루션</strong>을 제공합니다.
|
||||
<!-- 2. meta (H1 바로 다음 줄) -->
|
||||
<meta itemprop="name" :content="`${siteName} - 부산 중등 수학 과외 · 부산 중등 과외 1:1 매칭`" />
|
||||
<meta itemprop="description" content="부산 중등 수학 과외, 부산 중등 과외부터 초등·고등 국영수사과 1:1 방문·화상 맞춤 과외 매칭 및 과외비 투명 비교" />
|
||||
<meta itemprop="keywords" content="부산 중등 수학 과외, 부산 중등 과외, 부산 고등 수학 과외, 부산 고등 과외, 부산 초등 수학 과외, 부산 초등 과외, 부산 중등 영어 과외, 부산 과외, 우동 과외" />
|
||||
<meta itemprop="image" :content="`${siteDomain}/img/math-tutoring.png`" />
|
||||
<link itemprop="url" :href="`${siteDomain}/`" />
|
||||
<!-- 3. H2 (meta 바로 다음 줄) -->
|
||||
<h2 class="hero-subtitle text-base sm:text-lg font-bold text-slate-700 mb-3">부산 중등 과외 · 초등·고등 국영수사과 검증된 전문 선생님 100% 1:1 매칭</h2>
|
||||
<!-- 4. 일반글 p (H2 바로 다음 줄) -->
|
||||
<p class="hero-desc text-sm sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-8">
|
||||
부산 중등 수학 과외 및 부산 중등 과외, 초등·고등 전 과목 과외 비용·시세 투명 비교부터 검증된 전문 선생님 무료 시범수업까지 학생에게 꼭 맞는 1:1 맞춤 수업을 제공합니다.
|
||||
</p>
|
||||
|
||||
<!-- 4대 핵심 신뢰 보증 지표 (Trust Bar) -->
|
||||
@@ -400,29 +406,32 @@
|
||||
</section>
|
||||
|
||||
<!-- 5. 과목별 1:1 맞춤과외 갤러리 캐러셀 (클릭 시 확대 모달 및 상담/이동) -->
|
||||
<SubjectCarousel grade="초·중·고" />
|
||||
<SubjectCarousel :regionDong="defaultDong" shortSido="부산" grade="중학생" gradeShort="중등" />
|
||||
|
||||
<!-- 6. FAQ 섹션 (정돈된 아코디언) -->
|
||||
<!-- 6. FAQ 섹션 (네이티브 details/summary 시맨틱 구조) -->
|
||||
<section class="mt-16 px-4 sm:px-6 max-w-4xl mx-auto">
|
||||
<header class="text-center mb-8">
|
||||
<span class="text-xs sm:text-sm font-bold text-slate-400 tracking-wider">FAQ</span>
|
||||
<h2 class="text-2xl sm:text-3xl font-extrabold text-slate-900 mt-1 tracking-tight">자주 묻는 질문</h2>
|
||||
<h2 class="text-2xl sm:text-3xl font-extrabold text-slate-900 mt-1 tracking-tight">부산 중등 수학 과외 · 부산 중등 과외 자주 묻는 질문</h2>
|
||||
<p class="text-xs sm:text-sm text-slate-500 mt-1">부산 학부모님들께서 가장 많이 문의하시는 과외 진행 절차입니다.</p>
|
||||
</header>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div v-for="(faq, idx) in faqs" :key="idx" class="border border-slate-200 rounded-xl overflow-hidden bg-white shadow-xs">
|
||||
<button @click="faq.open = !faq.open" class="w-full p-4 sm:p-5 text-left text-sm sm:text-base font-bold text-slate-800 flex justify-between items-center hover:bg-slate-50 transition">
|
||||
<details v-for="(faq, idx) in faqs" :key="idx" :open="idx === 0" class="qa border border-slate-200 rounded-xl overflow-hidden bg-white shadow-xs group">
|
||||
<summary class="w-full p-4 sm:p-5 text-left text-sm sm:text-base font-bold text-slate-800 cursor-pointer list-none flex justify-between items-center hover:bg-slate-50 transition">
|
||||
<span>{{ faq.q }}</span>
|
||||
<i class="fa-solid fa-chevron-down text-xs sm:text-sm text-slate-400 transition-transform" :class="{ 'rotate-180': faq.open }"></i>
|
||||
</button>
|
||||
<div v-show="faq.open" class="p-4 sm:p-5 pt-0 text-xs sm:text-sm text-slate-600 leading-relaxed border-t border-slate-100 bg-slate-50/50">
|
||||
<i class="fa-solid fa-chevron-down text-xs sm:text-sm text-slate-400 transition-transform group-open:rotate-180"></i>
|
||||
</summary>
|
||||
<div class="ans p-4 sm:p-5 pt-3 text-xs sm:text-sm text-slate-600 leading-relaxed border-t border-slate-100 bg-slate-50/50">
|
||||
{{ faq.a }}
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 7. 관내 학년·과목·지역별 내부 연계 허브 (SSR SEO 크롤링 최적화) -->
|
||||
<InternalLinkHub :regionDong="defaultDong" grade="중학생" subjectName="수학" />
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
@@ -434,6 +443,7 @@ import { ref, reactive, computed, onMounted } from 'vue'
|
||||
const config = useRuntimeConfig()
|
||||
const siteName = config.public.siteName || '공부짝꿍'
|
||||
const siteDomain = config.public.siteDomain || 'https://soohyun.cloud'
|
||||
const defaultDong = '우동'
|
||||
|
||||
const isSubmitting = ref(false)
|
||||
const submitSuccess = ref(false)
|
||||
@@ -548,23 +558,23 @@ function formatPhone(e) {
|
||||
|
||||
const faqs = reactive([
|
||||
{
|
||||
q: '무료 시범수업은 어떻게 진행되나요?',
|
||||
a: '신청서 접수 후 부산 전담 매니저가 유선으로 학생의 성향과 목표를 파악한 뒤, 가장 적합한 전문 선생님을 배정해 드립니다. 배정된 선생님이 1:1 방문 또는 화상으로 40~50분간 모의 수업 및 취약점 진단을 무료로 진행하며, 수업 후 계속 진행 여부를 편안하게 결정하실 수 있습니다.',
|
||||
q: '부산 중등 수학 과외 · 부산 중등 과외 무료 시범수업은 어떻게 진행되나요?',
|
||||
a: '부산 중등 수학 과외 및 부산 중등 과외 신청서 접수 후 부산 전담 매니저가 유선으로 학생의 성향과 목표를 파악한 뒤 가장 적합한 부산 초·중·고 과외 전문 선생님을 배정해 드립니다. 배정된 선생님이 1:1 방문 또는 화상으로 40~50분간 모의 수업 및 취약점 진단을 무료로 진행하며, 수업 후 계속 진행 여부를 편안하게 결정하실 수 있습니다.',
|
||||
open: true
|
||||
},
|
||||
{
|
||||
q: '과외 비용 및 시세는 어떻게 되나요?',
|
||||
a: '학년(초등/중등/고등)과 주당 수업 횟수(주 1회, 주 2회 등), 수업 시간(회당 60분~120분)에 따라 교육청 가이드라인에 맞춘 투명한 표준 시세로 책정됩니다. 상담 시 거품 없는 정확한 부산 우리 동네 과외 비용을 안내해 드립니다.',
|
||||
q: '부산 중등 수학 과외 및 부산 초·중·고 과외 비용·시세는 어떻게 되나요?',
|
||||
a: '부산 중등 수학 과외, 부산 중등 과외, 부산 초·중·고 과외 비용은 학년(초등/중등/고등)과 주당 수업 횟수(주 1회, 주 2회 등), 수업 시간(회당 60분~120분)에 따라 교육청 가이드라인에 맞춘 투명한 표준 시세로 책정됩니다. 상담 시 거품 없는 정확한 부산 우리 동네 과외 비용을 안내해 드립니다.',
|
||||
open: false
|
||||
},
|
||||
{
|
||||
q: '선생님 신원과 학력 검증은 어떻게 이루어지나요?',
|
||||
a: '모든 강사진은 주민등록초본, 대학/대학원 재학 및 졸업증명서, 성범죄 경력 조회 등 엄격한 4단계 서류 검증과 교육청 개인과외교습자 신고를 100% 완료한 검증된 전문 선생님입니다.',
|
||||
q: '부산 중등 과외 · 부산 초·중·고 과외 선생님 신원과 학력 검증은 어떻게 이루어지나요?',
|
||||
a: '부산 중등 수학 과외 및 부산 중등 과외 모든 강사진은 주민등록초본, 대학/대학원 재학 및 졸업증명서, 성범죄 경력 조회 등 엄격한 4단계 서류 검증과 교육청 개인과외교습자 신고를 100% 완료한 검증된 부산 초·중·고 과외 전문 선생님입니다.',
|
||||
open: false
|
||||
},
|
||||
{
|
||||
q: '선생님이 아이와 맞지 않으면 어떻게 하나요?',
|
||||
a: '무료 시범수업을 통해 사전에 호흡을 맞출 수 있으며, 정규 수업 진행 중에도 선생님 교체를 희망하시면 추가 비용 없이 100% 만족하실 때까지 새로운 선생님으로 무료 재매칭을 진행해 드립니다.',
|
||||
q: '부산 중등 수학 과외 선생님이 아이와 맞지 않으면 교체가 가능한가요?',
|
||||
a: '부산 중등 수학 과외 및 부산 중등 과외는 무료 시범수업을 통해 사전에 호흡을 맞출 수 있으며, 부산 초·중·고 과외 정규 수업 진행 중에도 선생님 교체를 희망하시면 추가 비용 없이 100% 만족하실 때까지 새로운 선생님으로 무료 재매칭을 진행해 드립니다.',
|
||||
open: false
|
||||
}
|
||||
])
|
||||
@@ -608,46 +618,88 @@ async function handleSubmit() {
|
||||
// SEO 태그 설정 (지역 기반 + 고의도 롱테일 키워드 30~35자 내외 글자 수 준수)
|
||||
// SEO 태그 및 소셜 메타데이터 (네이버/구글 검색 최적화 및 3종 구조화 데이터 JSON-LD)
|
||||
useHead({
|
||||
title: '가온에듀 | 부산 초·중·고 검증된 맞춤 과외 매칭',
|
||||
title: `부산 중등 수학 과외 · 부산 중등 과외 | 초·중·고 1:1 맞춤 과외 ${siteName}`,
|
||||
link: [
|
||||
{ rel: 'canonical', href: 'https://soohyun.cloud/' }
|
||||
],
|
||||
meta: [
|
||||
{ name: 'robots', content: 'index,follow' },
|
||||
{ name: 'naver-site-verification', content: 'ec58dcc43a4785d3358d9e2b603fea6bea4d89a3' },
|
||||
{ name: 'description', content: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 명문대 및 베테랑 전문 강사진 1:1 맞춤 배정 솔루션' },
|
||||
{ name: 'description', content: `부산 중등 수학 과외, 부산 중등 과외, 우동 중등 수학 과외 전문 ${siteName}! 부산 초·중·고 국영수사과 1:1 방문·화상 맞춤 수업, 과외 비용·시세 투명 비교부터 무료 시범수업 신청까지.` },
|
||||
{ name: 'keywords', content: '부산 중등 수학 과외, 부산 중등 과외, 부산 고등 수학 과외, 부산 고등 과외, 부산 초등 수학 과외, 부산 초등 과외, 부산 중등 영어 과외, 부산 고등 영어 과외, 부산 과외, 우동 과외, 우동 중등 수학 과외' },
|
||||
{ property: 'og:type', content: 'website' },
|
||||
{ property: 'og:site_name', content: '가온에듀' },
|
||||
{ property: 'og:title', content: '가온에듀 | 부산 초·중·고 맞춤 과외 매칭' },
|
||||
{ property: 'og:description', content: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 검증된 전문 선생님 100% 매칭' },
|
||||
{ property: 'og:locale', content: 'ko_KR' },
|
||||
{ property: 'og:site_name', content: siteName },
|
||||
{ property: 'og:title', content: `부산 중등 수학 과외 · 부산 중등 과외 | 초·중·고 1:1 맞춤 과외 ${siteName}` },
|
||||
{ property: 'og:description', content: `부산 중등 수학 과외, 부산 중등 과외, 우동 중등 수학 과외 전문 ${siteName}! 과외 비용·시세 투명 비교부터 무료 시범수업 신청까지 검증된 전문 선생님 100% 매칭` },
|
||||
{ property: 'og:url', content: 'https://soohyun.cloud/' },
|
||||
{ property: 'og:image', content: 'https://soohyun.cloud/img/og-main.png' },
|
||||
{ property: 'og:image:type', content: 'image/png' },
|
||||
{ property: 'og:image:width', content: '1200' },
|
||||
{ property: 'og:image:height', content: '630' },
|
||||
{ property: 'og:image:alt', content: '부산 중등 수학 과외 · 부산 중등 과외' },
|
||||
{ name: 'twitter:card', content: 'summary_large_image' },
|
||||
{ name: 'twitter:title', content: '가온에듀 | 부산 초·중·고 맞춤 과외 매칭' },
|
||||
{ name: 'twitter:description', content: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 검증된 전문 선생님 100% 매칭' },
|
||||
{ name: 'twitter:title', content: `부산 중등 수학 과외 · 부산 중등 과외 | 초·중·고 1:1 맞춤 과외 ${siteName}` },
|
||||
{ name: 'twitter:description', content: `부산 중등 수학 과외, 부산 중등 과외, 우동 중등 수학 과외 전문 ${siteName}! 과외 비용·시세 투명 비교부터 무료 시범수업 신청까지 검증된 전문 선생님 100% 매칭` },
|
||||
{ name: 'twitter:image', content: 'https://soohyun.cloud/img/og-main.png' }
|
||||
],
|
||||
script: [
|
||||
// 1. EducationalOrganization / LocalBusiness 스키마
|
||||
// 1. @graph (WebSite + WebPage + ImageObject + EducationalOrganization / LocalBusiness)
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': ['EducationalOrganization', 'LocalBusiness'],
|
||||
name: '가온에듀',
|
||||
telephone: '+82-10-5961-5807',
|
||||
url: 'https://soohyun.cloud/',
|
||||
image: 'https://soohyun.cloud/img/og-main.png',
|
||||
address: {
|
||||
'@type': 'PostalAddress',
|
||||
streetAddress: '센텀중앙로 78 센텀타워 6층',
|
||||
addressLocality: '해운대구',
|
||||
addressRegion: '부산광역시',
|
||||
addressCountry: 'KR'
|
||||
},
|
||||
description: '부산 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관',
|
||||
areaServed: '부산광역시 전지역'
|
||||
'@graph': [
|
||||
{
|
||||
'@type': 'WebSite',
|
||||
'@id': `${siteDomain}/#site`,
|
||||
url: `${siteDomain}/`,
|
||||
name: siteName,
|
||||
inLanguage: 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'WebPage',
|
||||
'@id': `${siteDomain}/#page`,
|
||||
url: `${siteDomain}/`,
|
||||
name: `부산 중등 수학 과외 · 부산 중등 과외 | 초·중·고 1:1 맞춤 과외 ${siteName}`,
|
||||
description: `부산 중등 수학 과외, 부산 중등 과외, 우동 중등 수학 과외 전문 ${siteName}! 부산 초·중·고 국영수사과 1:1 방문·화상 맞춤 수업`,
|
||||
isPartOf: { '@id': `${siteDomain}/#site` },
|
||||
primaryImageOfPage: { '@id': `${siteDomain}/#img` },
|
||||
inLanguage: 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'ImageObject',
|
||||
'@id': `${siteDomain}/#img`,
|
||||
url: `${siteDomain}/img/math-tutoring.png`,
|
||||
contentUrl: `${siteDomain}/img/math-tutoring.png`,
|
||||
width: 1080,
|
||||
height: 1080,
|
||||
caption: '부산 중등 수학 과외 · 부산 중등 과외'
|
||||
},
|
||||
{
|
||||
'@type': ['EducationalOrganization', 'LocalBusiness'],
|
||||
name: siteName,
|
||||
telephone: '+82-10-5961-5807',
|
||||
url: `${siteDomain}/`,
|
||||
image: [
|
||||
`${siteDomain}/img/og-main.png`,
|
||||
`${siteDomain}/img/math-tutoring.png`,
|
||||
`${siteDomain}/img/english-tutoring.png`,
|
||||
`${siteDomain}/img/korean-tutoring.png`,
|
||||
`${siteDomain}/img/science-tutoring.png`,
|
||||
`${siteDomain}/img/social-studies-tutoring.png`
|
||||
],
|
||||
address: {
|
||||
'@type': 'PostalAddress',
|
||||
streetAddress: '센텀중앙로 78 센텀타워 6층',
|
||||
addressLocality: '해운대구',
|
||||
addressRegion: '부산광역시',
|
||||
addressCountry: 'KR'
|
||||
},
|
||||
description: '부산 중등 수학 과외, 부산 중등 과외 및 부산 초·중·고 1:1 맞춤 과외 전문 교육 기관',
|
||||
areaServed: '부산광역시 전지역'
|
||||
}
|
||||
]
|
||||
})
|
||||
},
|
||||
// 2. FAQPage 스키마
|
||||
@@ -666,50 +718,56 @@ useHead({
|
||||
}))
|
||||
})
|
||||
},
|
||||
// 3. ItemList 과목별 갤러리 섹션 스키마
|
||||
// 3. ItemList 과목별 및 학년별 갤러리 섹션 스키마 (더세이브 최상위 name/url/image + Google Course 리치 결과)
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'ItemList',
|
||||
name: '과목별 1:1 맞춤 과외 프로그램',
|
||||
name: `부산 중등 수학 과외 · 부산 중등 과외 프로그램`,
|
||||
itemListElement: [
|
||||
{
|
||||
{ sub: '수학', grade: '중학생', title: '부산 중등 수학 과외 · 우동 중학생 수학과외', desc: '개념 구멍 추적 및 킬러 문항 1:1 완파', img: 'math-tutoring.png' },
|
||||
{ sub: '영어', grade: '중학생', title: '부산 중등 영어 과외 · 우동 중학생 영어과외', desc: '교과서·부교재 전 지문 변형 및 서술형 영작', img: 'english-tutoring.png' },
|
||||
{ sub: '국어', grade: '중학생', title: '부산 중등 국어 과외 · 우동 중학생 국어과외', desc: '비문학 독해 논리와 교과서 문학 1:1 정밀 분석', img: 'korean-tutoring.png' },
|
||||
{ sub: '과학', grade: '중학생', title: '부산 중등 과학 과외 · 우동 중학생 과학과외', desc: '통합과학 원리 이해 및 물화생지 킬러 단원 정복', img: 'science-tutoring.png' },
|
||||
{ sub: '사회', grade: '중학생', title: '부산 중등 사회 과외 · 우동 중학생 사회과외', desc: '통합사회·한국사 핵심 흐름 및 사탐 만점 전략', img: 'social-studies-tutoring.png' },
|
||||
{ sub: '수학', grade: '초등학생', title: '부산 초등 수학 과외 · 우동 초등학생 수학과외', desc: '초등 기초 연산부터 중등 과정 개념 선행까지 1:1 맞춤 지도', img: 'math-tutoring.png' },
|
||||
{ sub: '수학', grade: '고등학생', title: '부산 고등 수학 과외 · 우동 고등학생 수학과외', desc: '부산 관내 고교 기출 족보 분석 및 수능·내신 1등급 완파', img: 'math-tutoring.png' },
|
||||
{ sub: '영어', grade: '고등학생', title: '부산 고등 영어 과외 · 우동 고등학생 영어과외', desc: '고등 내신 서술형 영작 첨삭 및 모의고사 1등급 구문 독해', img: 'english-tutoring.png' }
|
||||
].map((item, idx) => {
|
||||
const courseUrl = `${siteDomain}/${encodeURIComponent(defaultDong)}/${encodeURIComponent(item.grade)}/${encodeURIComponent(item.sub)}`
|
||||
const imgUrl = `${siteDomain}/img/${item.img}`
|
||||
return {
|
||||
'@type': 'ListItem',
|
||||
position: 1,
|
||||
name: '수학과외',
|
||||
description: '개념 구멍 추적 및 킬러 문항 1:1 완파',
|
||||
image: 'https://soohyun.cloud/img/math-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 2,
|
||||
name: '영어과외',
|
||||
description: '교과서·부교재 전 지문 변형 및 서술형 영작',
|
||||
image: 'https://soohyun.cloud/img/english-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 3,
|
||||
name: '국어과외',
|
||||
description: '비문학 독해 논리와 교과서 문학 1:1 정밀 분석',
|
||||
image: 'https://soohyun.cloud/img/korean-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 4,
|
||||
name: '과학과외',
|
||||
description: '통합과학 원리 이해 및 물화생지 킬러 단원 정복',
|
||||
image: 'https://soohyun.cloud/img/science-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 5,
|
||||
name: '사회과외',
|
||||
description: '통합사회·한국사 핵심 흐름 및 사탐 만점 전략',
|
||||
image: 'https://soohyun.cloud/img/social-studies-tutoring.png'
|
||||
position: idx + 1,
|
||||
name: item.title,
|
||||
url: courseUrl,
|
||||
image: imgUrl,
|
||||
item: {
|
||||
'@type': 'Course',
|
||||
name: item.title,
|
||||
description: item.desc,
|
||||
url: courseUrl,
|
||||
image: imgUrl,
|
||||
provider: {
|
||||
'@type': 'Organization',
|
||||
name: siteName,
|
||||
sameAs: siteDomain
|
||||
},
|
||||
offers: {
|
||||
'@type': 'Offer',
|
||||
category: 'Paid',
|
||||
priceCurrency: 'KRW',
|
||||
availability: 'https://schema.org/InStock',
|
||||
url: courseUrl
|
||||
},
|
||||
hasCourseInstance: {
|
||||
'@type': 'CourseInstance',
|
||||
courseMode: ['onsite', 'online']
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
</defs>
|
||||
<rect width="1200" height="630" fill="url(#bg)"/>
|
||||
<rect x="80" y="80" width="160" height="48" rx="8" fill="#fbbf24"/>
|
||||
<text x="160" y="112" font-family="'Pretendard', sans-serif" font-size="22" font-weight="900" fill="#1e293b" text-anchor="middle">AESEO</text>
|
||||
<text x="160" y="112" font-family="'Pretendard', sans-serif" font-size="22" font-weight="900" fill="#1e293b" text-anchor="middle">공부짝꿍</text>
|
||||
<text x="80" y="240" font-family="'Pretendard', sans-serif" font-size="56" font-weight="900" fill="#ffffff">우리 동네 초·중·고 1:1 맞춤 과외</text>
|
||||
<text x="80" y="320" font-family="'Pretendard', sans-serif" font-size="68" font-weight="900" fill="#fbbf24">내신 1등급 전문 과외애서</text>
|
||||
<text x="80" y="320" font-family="'Pretendard', sans-serif" font-size="68" font-weight="900" fill="#fbbf24">내신 1등급 전문 공부짝꿍</text>
|
||||
<text x="80" y="420" font-family="'Pretendard', sans-serif" font-size="30" font-weight="500" fill="#e0e7ff">국어 · 영어 · 수학 · 과학 · 사회 · 수행평가 세특</text>
|
||||
<text x="80" y="480" font-family="'Pretendard', sans-serif" font-size="28" font-weight="700" fill="#ffffff">전국 568개 동 학교별 기출 족보 완벽 분석</text>
|
||||
<rect x="80" y="530" width="340" height="50" rx="25" fill="#10b981"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -83,7 +83,7 @@
|
||||
|
||||
<!-- 성적 상승 그래프 비주얼 -->
|
||||
<text x="35" y="55" fill="#f8fafc" font-size="18" font-weight="800" font-family="'Pretendard', sans-serif">
|
||||
AESEO 성적 향상 지표
|
||||
공부짝꿍 성적 향상 지표
|
||||
</text>
|
||||
<text x="35" y="80" fill="#94a3b8" font-size="13" font-family="'Pretendard', sans-serif">
|
||||
수강생 평균 2.3등급 수직 상승
|
||||
@@ -96,7 +96,7 @@
|
||||
<text x="32" y="55" fill="#94a3b8" font-size="13" font-weight="700" text-anchor="middle">4등급</text>
|
||||
<text x="32" y="185" fill="#94a3b8" font-size="12" text-anchor="middle">수강 전</text>
|
||||
|
||||
<!-- 과외애서 수강 후 바 -->
|
||||
<!-- 공부짝꿍 수강 후 바 -->
|
||||
<rect x="95" y="10" width="75" height="150" rx="6" fill="url(#goldGrad)" />
|
||||
<text x="132" y="-5" fill="#f59e0b" font-size="16" font-weight="900" text-anchor="middle">1등급!</text>
|
||||
<text x="132" y="185" fill="#ffffff" font-size="13" font-weight="800" text-anchor="middle">수강 3개월</text>
|
||||
@@ -118,7 +118,7 @@
|
||||
|
||||
<!-- 우측 하단 워터마크 -->
|
||||
<text x="355" y="325" fill="#ffffff" opacity="0.3" font-size="13" font-weight="800" text-anchor="end" font-family="'Pretendard', sans-serif">
|
||||
AESEO TUTORING POSTER
|
||||
공부짝꿍 TUTORING POSTER
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
@@ -1,26 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title><![CDATA[가온에듀]]></title>
|
||||
<title><![CDATA[공부짝꿍]]></title>
|
||||
<link>https://soohyun.cloud/</link>
|
||||
<description><![CDATA[부산 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관]]></description>
|
||||
<language>ko</language>
|
||||
<pubDate>Tue, 20 Oct 2026 03:35:57 GMT</pubDate>
|
||||
<lastBuildDate>Tue, 20 Oct 2026 03:35:57 GMT</lastBuildDate>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<lastBuildDate>Wed, 04 Nov 2026 00:47:43 GMT</lastBuildDate>
|
||||
<atom:link href="https://soohyun.cloud/rss.xml" rel="self" type="application/rss+xml"/>
|
||||
<item>
|
||||
<title><![CDATA[부산 초·중·고 1:1 맞춤 과외 매칭]]></title>
|
||||
<link>https://soohyun.cloud/</link>
|
||||
<description><![CDATA[해운대·수영·동래 등 부산 전지역 과외 비용 비교 및 시범수업 신청]]></description>
|
||||
<pubDate>Tue, 20 Oct 2026 03:35:57 GMT</pubDate>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<guid>https://soohyun.cloud/</guid>
|
||||
</item>
|
||||
<item>
|
||||
<title><![CDATA[우동 중학생 수학과외 1:1 맞춤 수업]]></title>
|
||||
<link>https://soohyun.cloud/%EC%9A%B0%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</link>
|
||||
<description><![CDATA[해운대구 관내 학교 기출 분석]]></description>
|
||||
<pubDate>Tue, 20 Oct 2026 03:35:57 GMT</pubDate>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<guid>https://soohyun.cloud/%EC%9A%B0%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</guid>
|
||||
</item>
|
||||
<item>
|
||||
<title><![CDATA[사직동 고등학생 영어과외 1:1 맞춤 수업]]></title>
|
||||
<link>https://soohyun.cloud/%EC%82%AC%EC%A7%81%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</link>
|
||||
<description><![CDATA[동래구 사직동 내신 서술형 집중 대비]]></description>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<guid>https://soohyun.cloud/%EC%82%AC%EC%A7%81%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</guid>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
|
||||
@@ -29,8 +29,8 @@ export default defineEventHandler(async (event) => {
|
||||
}
|
||||
|
||||
const webhookUrl = config.discordWebhookUrl || 'https://discordapp.com/api/webhooks/1557204310369116210/9J4y96kmSbYNGtw5OxRgIz7InWcM8o3f8UX0Ad71-IyofwdS7tWmXkF7dj457-I8Ypiu'
|
||||
const siteName = config.public.siteName || '1:1 맞춤과외'
|
||||
const siteDomain = config.public.siteDomain || 'https://aeseo.cloud'
|
||||
const siteName = config.public.siteName || '공부짝꿍'
|
||||
const siteDomain = config.public.siteDomain || 'https://soohyun.cloud'
|
||||
|
||||
// 한국 시간 (KST)
|
||||
const now = new Date()
|
||||
@@ -53,7 +53,7 @@ export default defineEventHandler(async (event) => {
|
||||
{
|
||||
title: `[신규 무료 상담 신청 접수] ${finalLocation} - ${finalGrade} (${finalStudentName} 학생)`,
|
||||
description: `**${siteName}** 사이트에서 새로운 1:1 학습 상담 신청이 접수되었습니다.`,
|
||||
color: 0x991b1b, // 신뢰감 있는 딥 레드/네이비
|
||||
color: 0x991b1b,
|
||||
fields: [
|
||||
{
|
||||
name: "[접수 사이트]",
|
||||
|
||||
@@ -4,24 +4,42 @@ export default defineEventHandler((event) => {
|
||||
const config = useRuntimeConfig()
|
||||
const baseUrl = config.public.siteDomain || 'https://soohyun.cloud'
|
||||
const list = regionsData.list as Array<{ sido: string, sigungu: string, dong: string }>
|
||||
const today = new Date().toISOString().split('T')[0]
|
||||
|
||||
const subjects = ['영어', '수학', '국어', '통합과학', '통합사회']
|
||||
const grades = ['중학생', '고등학생']
|
||||
const subjects = ['수학', '영어', '국어', '과학', '사회']
|
||||
const grades = ['초등학생', '중학생', '고등학생']
|
||||
const subjectImages: Record<string, string> = {
|
||||
'수학': `${baseUrl}/img/math-tutoring.png`,
|
||||
'영어': `${baseUrl}/img/english-tutoring.png`,
|
||||
'국어': `${baseUrl}/img/korean-tutoring.png`,
|
||||
'과학': `${baseUrl}/img/science-tutoring.png`,
|
||||
'사회': `${baseUrl}/img/social-studies-tutoring.png`
|
||||
}
|
||||
|
||||
let xml = `<?xml version="1.0" encoding="UTF-8"?>\n`
|
||||
xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n`
|
||||
xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">\n`
|
||||
|
||||
// 메인
|
||||
xml += ` <url>\n <loc>${baseUrl}/</loc>\n <changefreq>daily</changefreq>\n <priority>1.0</priority>\n </url>\n`
|
||||
xml += ` <url>\n <loc>${baseUrl}/</loc>\n <lastmod>${today}</lastmod>\n <changefreq>daily</changefreq>\n <priority>1.0</priority>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/og-main.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/math-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/english-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/korean-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/science-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/social-studies-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` </url>\n`
|
||||
|
||||
// 568개 동별 주요 과목 및 학년 URL 생성
|
||||
// 동별 주요 과목 및 학년 URL 생성 (슬래시 라우터 구조 통일)
|
||||
list.forEach(r => {
|
||||
// 1. 동 대표
|
||||
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(r.dong)}</loc>\n <changefreq>weekly</changefreq>\n <priority>0.8</priority>\n </url>\n`
|
||||
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(r.dong)}</loc>\n <lastmod>${today}</lastmod>\n <changefreq>weekly</changefreq>\n <priority>0.8</priority>\n <image:image><image:loc>${baseUrl}/img/math-tutoring.png</image:loc></image:image>\n </url>\n`
|
||||
|
||||
// 2. 동-과목-학년 대표 조합
|
||||
subjects.slice(0, 3).forEach(sub => {
|
||||
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(r.dong)}-${encodeURIComponent(grades[0])}-${encodeURIComponent(sub)}</loc>\n <changefreq>weekly</changefreq>\n <priority>0.7</priority>\n </url>\n`
|
||||
// 2. 동/학년/과목 조합
|
||||
grades.forEach(g => {
|
||||
subjects.forEach(sub => {
|
||||
const imgLoc = subjectImages[sub] || `${baseUrl}/img/math-tutoring.png`
|
||||
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(r.dong)}/${encodeURIComponent(g)}/${encodeURIComponent(sub)}</loc>\n <lastmod>${today}</lastmod>\n <changefreq>weekly</changefreq>\n <priority>0.7</priority>\n <image:image><image:loc>${imgLoc}</image:loc></image:image>\n </url>\n`
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -17,10 +17,12 @@ export interface ParsedRouteParams {
|
||||
dong: string
|
||||
shortRegionName: string
|
||||
grade: string
|
||||
gradeShort: string
|
||||
subjectKey: string
|
||||
subjectName: string
|
||||
targetTerm: string
|
||||
fullKeyword: string
|
||||
isRegionOnly?: boolean
|
||||
}
|
||||
|
||||
// 5대 핵심 과목 정의
|
||||
@@ -34,30 +36,34 @@ export const SUBJECTS_MAP: Record<string, { key: string, name: string, badge: st
|
||||
|
||||
// 학년 정의
|
||||
export const GRADES_LIST = [
|
||||
{ key: 'middle', name: '중학생', aliases: ['중학생', '중1', '중2', '중3', '중등'] },
|
||||
{ key: 'high', name: '고등학생', aliases: ['고등학생', '고1', '고2', '고3', '고등', '예비고1'] },
|
||||
{ key: 'elem', name: '초등학생', aliases: ['초등학생', '초등', '초5', '초6'] }
|
||||
{ key: 'middle', name: '중학생', shortName: '중등', aliases: ['중학생', '중1', '중2', '중3', '중등'] },
|
||||
{ key: 'high', name: '고등학생', shortName: '고등', aliases: ['고등학생', '고1', '고2', '고3', '고등', '예비고1', 'N수', '재수'] },
|
||||
{ key: 'elem', name: '초등학생', shortName: '초등', aliases: ['초등학생', '초등', '초1', '초2', '초3', '초4', '초5', '초6'] }
|
||||
]
|
||||
|
||||
// 동 이름으로 지역 검색
|
||||
export function getRegionByDong(dongQuery: string): RegionInfo | null {
|
||||
if (!dongQuery) return null
|
||||
const clean = dongQuery.trim().replace(/동$/, '') // '황금' 또는 '황금동' 모두 매칭
|
||||
const clean = dongQuery.trim().replace(/[동읍면리가]$/, '')
|
||||
const map = regionsData.dongMap as Record<string, RegionInfo[]>
|
||||
|
||||
// 1. 정확 매칭 (황금동)
|
||||
// 1. 정확 매칭
|
||||
if (map[dongQuery] && map[dongQuery].length > 0) {
|
||||
return map[dongQuery][0]
|
||||
}
|
||||
// 2. '동' 붙여서 매칭
|
||||
if (map[dongQuery + '동'] && map[dongQuery + '동'].length > 0) {
|
||||
return map[dongQuery + '동'][0]
|
||||
// 2. '동', '읍', '면' 붙여서 매칭
|
||||
for (const suffix of ['동', '읍', '면']) {
|
||||
if (map[clean + suffix] && map[clean + suffix].length > 0) {
|
||||
return map[clean + suffix][0]
|
||||
}
|
||||
}
|
||||
// 3. 리스트 전체 순회 매칭
|
||||
const found = (regionsData.list as RegionInfo[]).find(r =>
|
||||
r.dong === dongQuery ||
|
||||
r.dong === (dongQuery + '동') ||
|
||||
r.dong.startsWith(clean)
|
||||
r.dong === (clean + '동') ||
|
||||
r.dong === (clean + '읍') ||
|
||||
r.dong === (clean + '면') ||
|
||||
(clean.length >= 2 && r.dong.startsWith(clean))
|
||||
)
|
||||
return found || null
|
||||
}
|
||||
@@ -99,12 +105,6 @@ export function getShortRegionName(sido: string, dong: string, sigungu?: string)
|
||||
}
|
||||
|
||||
// 지능형 URL 슬러그 파서
|
||||
// 지원 예시:
|
||||
// - ['대구광역시', '수성구', '황금동']
|
||||
// - ['대구광역시', '황금동', '중학생', '영어']
|
||||
// - ['황금동', '중학생', '영어']
|
||||
// - ['황금동-중학생-영어']
|
||||
// - '대구광역시-황금동-중학생-영어'
|
||||
export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams {
|
||||
let tokens: string[] = []
|
||||
|
||||
@@ -117,6 +117,7 @@ export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams
|
||||
|
||||
let matchedRegion: RegionInfo | null = null
|
||||
let detectedGrade = '중학생'
|
||||
let detectedGradeShort = '중등'
|
||||
let detectedSubjectKey = 'english'
|
||||
let detectedSubjectName = '영어'
|
||||
let detectedTerm = '과외'
|
||||
@@ -141,30 +142,37 @@ export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams
|
||||
}
|
||||
}
|
||||
|
||||
// 기본값 (568개 타겟 지역 중 첫 번째 기준)
|
||||
// 기본값 (타겟 지역 중 첫 번째 기준)
|
||||
if (!matchedRegion) {
|
||||
matchedRegion = (regionsData.list as RegionInfo[])[0] || {
|
||||
fullName: '경기도 고양시 덕양구 고양동',
|
||||
sido: '경기도',
|
||||
sigungu: '고양시 덕양구',
|
||||
dong: '고양동'
|
||||
fullName: '부산광역시 해운대구 우동',
|
||||
sido: '부산광역시',
|
||||
sigungu: '해운대구',
|
||||
dong: '우동'
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 학년 추출
|
||||
let hasExplicitGrade = false
|
||||
const fullText = tokens.join(' ')
|
||||
for (const g of GRADES_LIST) {
|
||||
if (g.aliases.some(a => fullText.includes(a))) {
|
||||
detectedGrade = g.name
|
||||
detectedGradeShort = g.shortName
|
||||
hasExplicitGrade = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const gradeShort = detectedGradeShort || (detectedGrade === '초등학생' ? '초등' : detectedGrade === '고등학생' ? '고등' : '중등')
|
||||
|
||||
// 4. 과목 추출
|
||||
let hasExplicitSubject = false
|
||||
for (const [key, sub] of Object.entries(SUBJECTS_MAP)) {
|
||||
if (sub.aliases.some(a => fullText.includes(a))) {
|
||||
detectedSubjectKey = key
|
||||
detectedSubjectName = sub.name
|
||||
hasExplicitSubject = true
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -188,10 +196,12 @@ export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams
|
||||
dong: matchedRegion.dong,
|
||||
shortRegionName,
|
||||
grade: detectedGrade,
|
||||
gradeShort,
|
||||
subjectKey: detectedSubjectKey,
|
||||
subjectName: detectedSubjectName,
|
||||
targetTerm: detectedTerm,
|
||||
fullKeyword
|
||||
fullKeyword,
|
||||
isRegionOnly: !hasExplicitGrade && !hasExplicitSubject
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,150 +1,315 @@
|
||||
import type { ParsedRouteParams } from './dataHelper'
|
||||
import type { ParsedRouteParams } from './dataHelper'
|
||||
import { getShortRegionName } from './dataHelper'
|
||||
|
||||
const SUBJECT_IMAGE_MAP: Record<string, string> = {
|
||||
math: '/img/math-tutoring.png',
|
||||
english: '/img/english-tutoring.png',
|
||||
korean: '/img/korean-tutoring.png',
|
||||
science: '/img/science-tutoring.png',
|
||||
social: '/img/social-studies-tutoring.png'
|
||||
}
|
||||
|
||||
const CORE_SUBJECTS = [
|
||||
{ key: 'math', name: '수학', desc: '개념 구멍 추적 및 킬러 문항 1:1 완파', img: '/img/math-tutoring.png' },
|
||||
{ key: 'english', name: '영어', desc: '교과서·부교재 전 지문 변형 및 서술형 영작', img: '/img/english-tutoring.png' },
|
||||
{ key: 'korean', name: '국어', desc: '비문학 독해 논리와 교과서 문학 1:1 정밀 분석', img: '/img/korean-tutoring.png' },
|
||||
{ key: 'science', name: '과학', desc: '통합과학 원리 이해 및 물화생지 킬러 단원 정복', img: '/img/science-tutoring.png' },
|
||||
{ key: 'social', name: '사회', desc: '통합사회·한국사 핵심 흐름 및 사탐 만점 전략', img: '/img/social-studies-tutoring.png' }
|
||||
]
|
||||
|
||||
const CORE_GRADES = ['초등학생', '중학생', '고등학생']
|
||||
|
||||
export function generateSeoMeta(parsed: ParsedRouteParams, siteName = '공부짝꿍', siteDomain = 'https://soohyun.cloud') {
|
||||
const { sido, sigungu, dong, shortRegionName, grade, subjectName, targetTerm, fullKeyword } = parsed
|
||||
const { sido, sigungu, dong, shortRegionName, grade, subjectKey, subjectName, isRegionOnly } = parsed
|
||||
|
||||
const shortSido = parsed.shortSido || sido.replace(/특별시|광역시|특별자치시|도/g, '').trim()
|
||||
const gradeShort = parsed.gradeShort || (grade === '초등학생' ? '초등' : grade === '고등학생' ? '고등' : '중등')
|
||||
const regionTitle = shortRegionName || getShortRegionName(sido, dong)
|
||||
const subjectImg = SUBJECT_IMAGE_MAP[subjectKey] || '/img/math-tutoring.png'
|
||||
|
||||
// 학부모 검색 최적화: [지역] [과목]과외 전문 매칭 | [학년] 1:1 방문 맞춤 수업 (공백 포함 30~35자 내외 말줄임 방지)
|
||||
const pageTitle = `${regionTitle} ${subjectName}과외 전문 매칭 | ${grade} 1:1 방문 맞춤 수업`
|
||||
// 검색어 [지역] [초등/중등/고등] [과목] 과외 / [지역] [초등/중등/고등] 과외 완벽 매칭 타이틀
|
||||
const pageTitle = isRegionOnly
|
||||
? `${shortSido} 중등 수학 과외 · ${shortSido} 중등 과외 | ${regionTitle} 초·중·고 1:1 맞춤 과외`
|
||||
: `${shortSido} ${gradeShort} ${subjectName} 과외 · ${regionTitle} ${grade} ${subjectName}과외 | ${shortSido} ${gradeShort} 과외 1:1 매칭`
|
||||
|
||||
// 고의도 검색 및 전환 최적화 메타 디스크립션 (과외 비용 시세 + 학교 기출 분석 + 100% 신원 검증 + 무료 시범수업)
|
||||
const pageDescription = `${regionTitle} ${grade} ${subjectName}과외 전문 매칭. 과외 비용 및 시세 비교부터 무료 시범수업 신청까지. ${dong} 인근 학교별 기출 족보 완벽 분석, 서술형 감점 방지, 검증된 1:1 전문 선생님 100% 매칭.`
|
||||
// 첫 문장이 정확한 타겟 키워드로 시작하는 고의도 메타 디스크립션 (더세이브 동기화)
|
||||
const pageDescription = isRegionOnly
|
||||
? `${shortSido} 중등 수학 과외, ${shortSido} 중등 과외, ${dong} 중등 수학 과외 전문 ${siteName}! ${regionTitle} 초등·중등·고등 국영수사과 1:1 맞춤 과외, 검증된 전문 선생님 무료 시범수업과 과외비 비교를 확인하세요.`
|
||||
: `${shortSido} ${gradeShort} ${subjectName} 과외, ${shortSido} ${gradeShort} 과외, ${dong} ${gradeShort} ${subjectName} 과외 전문 ${siteName}! ${regionTitle} ${grade} ${subjectName} 1:1 방문·화상 맞춤 수업으로 내신·수능 성적 향상을 책임집니다. 과외비 투명 공개 및 무료 시범수업 신청하세요.`
|
||||
|
||||
// 표준 Canonical URL
|
||||
const canonicalUrl = `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(grade)}/${encodeURIComponent(subjectName)}`
|
||||
const pageKeywords = `${shortSido} ${gradeShort} ${subjectName} 과외, ${shortSido} ${gradeShort} 과외, ${dong} ${gradeShort} ${subjectName} 과외, ${dong} ${gradeShort} 과외, ${shortSido}${gradeShort}${subjectName}과외, ${shortSido}${gradeShort}과외, ${shortSido} 중등 수학 과외, ${shortSido} 중등 과외, ${shortSido} 고등 수학 과외, ${shortSido} 초등 수학 과외, ${regionTitle} ${subjectName}과외, ${dong} ${subjectName}과외, ${dong} ${grade} ${subjectName}과외, ${dong}과외, ${sigungu}과외, ${shortSido}과외`
|
||||
|
||||
const jsonLd = {
|
||||
// 표준 Canonical URL (자기참조 분리)
|
||||
const dongUrl = `${siteDomain}/${encodeURIComponent(dong)}`
|
||||
const canonicalUrl = isRegionOnly
|
||||
? dongUrl
|
||||
: `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(grade)}/${encodeURIComponent(subjectName)}`
|
||||
|
||||
// 더세이브 방식 멀티 이미지 배열
|
||||
const orgImages = [
|
||||
`${siteDomain}/img/og-main.png`,
|
||||
`${siteDomain}/img/math-tutoring.png`,
|
||||
`${siteDomain}/img/english-tutoring.png`,
|
||||
`${siteDomain}/img/korean-tutoring.png`,
|
||||
`${siteDomain}/img/science-tutoring.png`,
|
||||
`${siteDomain}/img/social-studies-tutoring.png`
|
||||
]
|
||||
|
||||
// 서브 라우터 캐러셀(ItemList) 항목 구성: 현재 동 기준 5대 과목 + 타 학년 라우터 (중복 제외 총 7개)
|
||||
const carouselCourses: Array<{ name: string, desc: string, url: string, image: string }> = []
|
||||
for (const sub of CORE_SUBJECTS) {
|
||||
const cUrl = `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(grade)}/${encodeURIComponent(sub.name)}`
|
||||
carouselCourses.push({
|
||||
name: `${shortSido} ${gradeShort} ${sub.name} 과외 · ${regionTitle} ${grade} ${sub.name}과외`,
|
||||
desc: `${dong} 관내 학교 내신 기출 분석 및 ${sub.desc}`,
|
||||
url: cUrl,
|
||||
image: `${siteDomain}${sub.img}`
|
||||
})
|
||||
}
|
||||
for (const g of CORE_GRADES) {
|
||||
if (g === grade) continue
|
||||
const gShort = g === '초등학생' ? '초등' : g === '고등학생' ? '고등' : '중등'
|
||||
const cUrl = `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(g)}/${encodeURIComponent(subjectName)}`
|
||||
carouselCourses.push({
|
||||
name: `${shortSido} ${gShort} ${subjectName} 과외 · ${regionTitle} ${g} ${subjectName}과외`,
|
||||
desc: `${dong} ${g} 학생 대상 ${subjectName} 내신·선행 1:1 밀착 지도`,
|
||||
url: cUrl,
|
||||
image: `${siteDomain}${subjectImg}`
|
||||
})
|
||||
}
|
||||
|
||||
const breadcrumbItems = isRegionOnly
|
||||
? [
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 1,
|
||||
'name': '홈',
|
||||
'item': `${siteDomain}/`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 2,
|
||||
'name': `${regionTitle} 과외`,
|
||||
'item': dongUrl
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 1,
|
||||
'name': '홈',
|
||||
'item': `${siteDomain}/`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 2,
|
||||
'name': `${dong} 과외`,
|
||||
'item': dongUrl
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 3,
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 · ${dong} ${grade} ${subjectName}과외`,
|
||||
'item': canonicalUrl
|
||||
}
|
||||
]
|
||||
|
||||
// 블록 1: @graph (WebSite + WebPage + ImageObject + EducationalOrganization + LocalBusiness + Course + BreadcrumbList)
|
||||
const graphJsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@graph': [
|
||||
{
|
||||
'@type': 'WebSite',
|
||||
'@id': `${siteDomain}/#site`,
|
||||
'url': `${siteDomain}/`,
|
||||
'name': siteName,
|
||||
'inLanguage': 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'WebPage',
|
||||
'@id': `${canonicalUrl}#page`,
|
||||
'url': canonicalUrl,
|
||||
'name': pageTitle,
|
||||
'description': pageDescription,
|
||||
'isPartOf': { '@id': `${siteDomain}/#site` },
|
||||
'primaryImageOfPage': { '@id': `${canonicalUrl}#img` },
|
||||
'inLanguage': 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'ImageObject',
|
||||
'@id': `${canonicalUrl}#img`,
|
||||
'url': `${siteDomain}${subjectImg}`,
|
||||
'contentUrl': `${siteDomain}${subjectImg}`,
|
||||
'width': 1080,
|
||||
'height': 1080,
|
||||
'caption': `${shortSido} ${gradeShort} ${subjectName} 과외`
|
||||
},
|
||||
{
|
||||
'@type': 'EducationalOrganization',
|
||||
'name': siteName,
|
||||
'url': siteDomain,
|
||||
'image': orgImages,
|
||||
'telephone': '+82-10-5961-5807',
|
||||
'description': pageDescription,
|
||||
'areaServed': {
|
||||
'@type': 'AdministrativeArea',
|
||||
'name': `${sido} ${sigungu} ${dong}`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Course',
|
||||
'name': `${dong} ${grade} ${subjectName} 1:1 맞춤 과외`,
|
||||
'description': `${dong} 인근 학교 내신 출제 경향 분석 및 ${subjectName} 1등급 도약 커리큘럼`,
|
||||
'provider': {
|
||||
'@type': 'Organization',
|
||||
'name': siteName
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'LocalBusiness',
|
||||
'name': `${regionTitle} 1:1 방문 과외`,
|
||||
'image': `${siteDomain}/img/og-preview.png`,
|
||||
'name': `${shortSido} ${gradeShort} 과외 · ${regionTitle} 1:1 방문 과외`,
|
||||
'image': orgImages,
|
||||
'url': canonicalUrl,
|
||||
'telephone': '+82-10-5961-5807',
|
||||
'priceRange': '₩₩',
|
||||
'address': {
|
||||
'@type': 'PostalAddress',
|
||||
'addressLocality': sido,
|
||||
'addressRegion': sigungu,
|
||||
'addressLocality': sigungu,
|
||||
'addressRegion': sido,
|
||||
'streetAddress': dong,
|
||||
'addressCountry': 'KR'
|
||||
},
|
||||
'areaServed': `${sido} ${sigungu} ${dong}`
|
||||
},
|
||||
{
|
||||
'@type': 'FAQPage',
|
||||
'mainEntity': [
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${dong} ${grade} ${subjectName} 방문 과외와 온라인 화상 과외 중 어떤 것이 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `학생과 학부모님의 선호에 따라 100% 자택 방문 대면 과외 또는 실시간 쌍방향 비대면 화상 과외 중 자유롭게 선택하실 수 있습니다. ${dong} 전 지역 방문 수업이 가능합니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${grade} ${subjectName} 전문 선생님이 학생과 잘 맞지 않으면 교체 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': '네, 1회 무료 모의수업을 통해 사전에 호흡을 맞추며, 정규 수업 시작 후에도 학생의 성향이나 요청에 따라 추가 비용 없이 100% 무료 교체 및 환불 규정을 보장합니다.'
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${grade} ${subjectName} 과외 수업 비용은 어떻게 되나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${grade} 내신 단계, 주당 수업 횟수, 수업 시간(1회 60분/90분/120분)에 따라 표준 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다. 무료 상담 시 상세 견적표를 안내해 드립니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${dong} 학교 중간·기말고사 직전 단기 ${subjectName} 족보 클리닉도 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, 시험 3~4주 전 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${grade} ${subjectName} 단기 속성 킬러 클리닉 프로그램도 상시 운영 중입니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${subjectName} 외에 다른 과목도 함께 상담받을 수 있나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${subjectName} 집중 신청은 물론, 국영수 또는 수탐 복합 패키지로 맞춤 구성하여 전 과목 플래너 관리와 함께 시간표를 편성하실 수 있습니다.`
|
||||
}
|
||||
}
|
||||
]
|
||||
'@type': 'Course',
|
||||
'name': isRegionOnly ? `${shortSido} 중등 수학 과외 · ${regionTitle} 초·중·고 1:1 맞춤 과외` : `${shortSido} ${gradeShort} ${subjectName} 과외 · ${dong} ${grade} ${subjectName} 1:1 맞춤 과외`,
|
||||
'description': `${shortSido} ${gradeShort} ${subjectName} 과외 및 ${dong} 인근 학교 내신 출제 경향 분석, ${subjectName} 1등급 도약 커리큘럼`,
|
||||
'url': canonicalUrl,
|
||||
'image': `${siteDomain}${subjectImg}`,
|
||||
'provider': {
|
||||
'@type': 'Organization',
|
||||
'name': siteName,
|
||||
'sameAs': siteDomain
|
||||
},
|
||||
'offers': {
|
||||
'@type': 'Offer',
|
||||
'category': 'Paid',
|
||||
'priceCurrency': 'KRW',
|
||||
'availability': 'https://schema.org/InStock',
|
||||
'url': canonicalUrl
|
||||
},
|
||||
'hasCourseInstance': {
|
||||
'@type': 'CourseInstance',
|
||||
'courseMode': ['onsite', 'online']
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'BreadcrumbList',
|
||||
'itemListElement': [
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 1,
|
||||
'name': '홈',
|
||||
'item': siteDomain
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 2,
|
||||
'name': sido,
|
||||
'item': `${siteDomain}/${encodeURIComponent(sido)}`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 3,
|
||||
'name': sigungu,
|
||||
'item': `${siteDomain}/${encodeURIComponent(sigungu)}`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 4,
|
||||
'name': `${dong} ${subjectName}`,
|
||||
'item': canonicalUrl
|
||||
}
|
||||
]
|
||||
'itemListElement': breadcrumbItems
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 블록 2: FAQPage 단독 JSON-LD
|
||||
const faqJsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'FAQPage',
|
||||
'mainEntity': [
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외(${dong}), 방문 수업과 화상 수업 모두 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, ${shortSido} ${gradeShort} ${subjectName} 과외 및 ${shortSido} ${gradeShort} 과외는 학생과 학부모님의 선호에 따라 100% 자택 방문 대면 수업 또는 실시간 쌍방향 화상 수업 중 자유롭게 선택하실 수 있으며, ${dong} ${gradeShort} ${subjectName} 과외 전 지역 방문 지도가 가능합니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} 과외 · ${dong} ${gradeShort} ${subjectName} 과외 전문 선생님이 학생과 맞지 않으면 교체 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, ${shortSido} ${gradeShort} ${subjectName} 과외 및 ${shortSido} ${gradeShort} 과외는 1회 무료 시범수업을 통해 사전에 호흡을 맞추며, ${dong} ${gradeShort} ${subjectName} 과외 정규 수업 시작 후에도 추가 비용 없이 100% 무료 선생님 교체 및 환불 규정을 보장합니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 및 ${dong} ${gradeShort} ${subjectName} 과외 수업 비용은 어떻게 되나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${shortSido} ${gradeShort} ${subjectName} 과외와 ${shortSido} ${gradeShort} 과외 비용은 ${grade} 내신 단계, 주당 수업 횟수, 수업 시간(1회 60분/90분/120분)에 따라 표준 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다. ${dong} ${gradeShort} ${subjectName} 과외 무료 상담 시 상세 견적표를 안내해 드립니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${dong} ${gradeShort} ${subjectName} 과외로 중간·기말고사 직전 단기 족보 클리닉도 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, ${shortSido} ${gradeShort} ${subjectName} 과외 및 ${shortSido} ${gradeShort} 과외 전담팀이 시험 3~4주 전 ${dong} 인근 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${dong} ${gradeShort} ${subjectName} 과외 단기 속성 클리닉도 상시 운영 중입니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 외에 국영수사과 다른 과목도 함께 상담받을 수 있나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${shortSido} ${gradeShort} ${subjectName} 과외 집중 신청은 물론, ${shortSido} ${gradeShort} 과외 국영수사과 복합 패키지 및 ${dong} ${gradeShort} ${subjectName} 과외 맞춤형 전 과목 플래너 관리로 시간표를 편성하실 수 있습니다.`
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 블록 3: ItemList 단독 JSON-LD (더세이브 검색결과 가로 이미지 줄 핵심 구조)
|
||||
const itemListJsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'ItemList',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 · ${dong} ${gradeShort} 과외`,
|
||||
'numberOfItems': carouselCourses.length,
|
||||
'itemListElement': carouselCourses.map((c, idx) => ({
|
||||
'@type': 'ListItem',
|
||||
'position': idx + 1,
|
||||
'name': c.name,
|
||||
'url': c.url,
|
||||
'image': c.image,
|
||||
'item': {
|
||||
'@type': 'Course',
|
||||
'name': c.name,
|
||||
'description': c.desc,
|
||||
'url': c.url,
|
||||
'image': c.image,
|
||||
'provider': {
|
||||
'@type': 'Organization',
|
||||
'name': siteName,
|
||||
'sameAs': siteDomain
|
||||
},
|
||||
'offers': {
|
||||
'@type': 'Offer',
|
||||
'category': 'Paid',
|
||||
'priceCurrency': 'KRW',
|
||||
'availability': 'https://schema.org/InStock',
|
||||
'url': c.url
|
||||
},
|
||||
'hasCourseInstance': {
|
||||
'@type': 'CourseInstance',
|
||||
'courseMode': ['onsite', 'online']
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
return {
|
||||
title: pageTitle,
|
||||
meta: [
|
||||
{ name: 'robots', content: 'index,follow' },
|
||||
{ name: 'naver-site-verification', content: 'ec58dcc43a4785d3358d9e2b603fea6bea4d89a3' },
|
||||
{ name: 'description', content: pageDescription },
|
||||
{ name: 'keywords', content: `${dong}과외, ${dong}${subjectName}과외, ${dong}${grade}과외, ${sigungu}과외, ${dong}학원, ${dong}내신대비, ${subjectName}1:1과외` },
|
||||
{ name: 'keywords', content: pageKeywords },
|
||||
{ property: 'og:type', content: 'website' },
|
||||
{ property: 'og:locale', content: 'ko_KR' },
|
||||
{ property: 'og:title', content: pageTitle },
|
||||
{ property: 'og:description', content: pageDescription },
|
||||
{ property: 'og:url', content: canonicalUrl },
|
||||
{ property: 'og:site_name', content: siteName },
|
||||
{ property: 'og:image', content: `${siteDomain}/img/og-preview.png` },
|
||||
{ property: 'og:image', content: `${siteDomain}${subjectImg}` },
|
||||
{ property: 'og:image:type', content: 'image/png' },
|
||||
{ property: 'og:image:width', content: '1200' },
|
||||
{ property: 'og:image:height', content: '630' },
|
||||
{ property: 'og:image:alt', content: `${shortSido} ${gradeShort} ${subjectName} 과외 · ${dong} ${gradeShort} ${subjectName} 과외` },
|
||||
{ name: 'twitter:card', content: 'summary_large_image' },
|
||||
{ name: 'twitter:title', content: pageTitle },
|
||||
{ name: 'twitter:description', content: pageDescription }
|
||||
{ name: 'twitter:description', content: pageDescription },
|
||||
{ name: 'twitter:image', content: `${siteDomain}${subjectImg}` }
|
||||
],
|
||||
link: [
|
||||
{ rel: 'canonical', href: canonicalUrl }
|
||||
@@ -152,7 +317,15 @@ export function generateSeoMeta(parsed: ParsedRouteParams, siteName = '공부짝
|
||||
script: [
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(jsonLd)
|
||||
children: JSON.stringify(graphJsonLd)
|
||||
},
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(faqJsonLd)
|
||||
},
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(itemListJsonLd)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,38 +2,33 @@
|
||||
<section class="faq-section">
|
||||
<div class="section-header">
|
||||
<span class="section-badge">궁금한 점을 풀어드립니다</span>
|
||||
<h2 class="section-title">{{ regionDong }} 1:1 과외 자주 묻는 질문</h2>
|
||||
<h2 class="section-title">{{ shortSido }} {{ gradeShort }} {{ subjectName }} 과외 · {{ regionDong }} 1:1 과외 자주 묻는 질문</h2>
|
||||
<p class="section-desc">학부모님들께서 가장 많이 문의하시는 내용을 모았습니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="faq-list">
|
||||
<div
|
||||
<details
|
||||
v-for="(faq, idx) in faqs"
|
||||
:key="idx"
|
||||
class="faq-item"
|
||||
:class="{ active: openIndex === idx }"
|
||||
class="faq-item qa"
|
||||
:open="idx === 0"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="faq-question"
|
||||
@click="toggle(idx)"
|
||||
:aria-expanded="openIndex === idx"
|
||||
>
|
||||
<summary class="faq-question">
|
||||
<span class="q-icon">Q</span>
|
||||
<span class="q-text">{{ faq.q }}</span>
|
||||
<span class="toggle-icon">{{ openIndex === idx ? '▲' : '▼' }}</span>
|
||||
</button>
|
||||
<div v-show="openIndex === idx" class="faq-answer">
|
||||
<span class="toggle-icon">▼</span>
|
||||
</summary>
|
||||
<div class="faq-answer ans">
|
||||
<span class="a-icon">A</span>
|
||||
<p class="a-text">{{ faq.a }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
regionDong: {
|
||||
@@ -44,38 +39,40 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: '중등'
|
||||
},
|
||||
shortSido: {
|
||||
type: String,
|
||||
default: '대구'
|
||||
},
|
||||
subjectName: {
|
||||
type: String,
|
||||
default: '영어'
|
||||
default: '수학'
|
||||
}
|
||||
})
|
||||
|
||||
const openIndex = ref(0)
|
||||
|
||||
const toggle = (idx) => {
|
||||
openIndex.value = openIndex.value === idx ? -1 : idx
|
||||
}
|
||||
|
||||
const faqs = computed(() => [
|
||||
{
|
||||
q: `${props.regionDong} ${props.grade} ${props.subjectName} 방문 과외와 온라인 화상 과외 중 어떤 것이 가능한가요?`,
|
||||
a: `학생과 학부모님의 선호에 따라 100% 자택 방문 대면 과외 또는 실시간 쌍방향 비대면 화상 과외 중 자유롭게 선택하실 수 있습니다. ${props.regionDong} 전 지역 방문 수업이 가능합니다.`
|
||||
q: `${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외 및 ${props.regionDong} ${props.grade} ${props.subjectName} 방문 과외와 화상 과외 중 어떤 것이 가능한가요?`,
|
||||
a: `학생과 학부모님의 선호에 따라 ${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외 100% 자택 방문 대면 수업 또는 실시간 쌍방향 화상 과외 중 자유롭게 선택하실 수 있습니다. ${props.regionDong} 전 지역 방문 수업이 가능합니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.grade} ${props.subjectName} 전문 선생님이 학생과 잘 맞지 않으면 교체 가능한가요?`,
|
||||
a: '네, 1회 무료 모의수업을 통해 사전에 호흡을 맞추며, 정규 수업 시작 후에도 학생의 성향이나 요청에 따라 추가 비용 없이 100% 무료 교체 및 환불 규정을 보장합니다.'
|
||||
q: `${props.shortSido} ${props.gradeShort} 과외 · ${props.regionDong} ${props.grade} ${props.subjectName} 전문 선생님이 학생과 맞지 않으면 교체 가능한가요?`,
|
||||
a: `네, ${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외는 1회 무료 모의수업을 통해 사전에 호흡을 맞추며, 정규 수업 시작 후에도 학생의 성향이나 요청에 따라 추가 비용 없이 100% 무료 교체 및 환불 규정을 보장합니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.grade} ${props.subjectName} 과외 수업 비용은 어떻게 되나요?`,
|
||||
a: `${props.grade} 내신 단계, 주당 수업 횟수, 수업 시간(1회 60분/90분/120분)에 따라 표준 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다. 무료 상담 시 상세 견적표를 안내해 드립니다.`
|
||||
q: `${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외 및 ${props.regionDong} ${props.grade} ${props.subjectName} 과외 수업 비용은 어떻게 되나요?`,
|
||||
a: `${props.shortSido} ${props.gradeShort} 과외는 ${props.grade} 내신 단계, 주당 수업 횟수, 수업 시간(1회 60분/90분/120분)에 따라 표준 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다. 무료 상담 시 상세 견적표를 안내해 드립니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.regionDong} 학교 중간·기말고사 직전 단기 ${props.subjectName} 족보 클리닉도 가능한가요?`,
|
||||
a: `네, 시험 3~4주 전 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${props.grade} ${props.subjectName} 단기 속성 킬러 클리닉 프로그램도 상시 운영 중입니다.`
|
||||
q: `${props.regionDong} 학교 중간·기말고사 직전 단기 ${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외 족보 클리닉도 가능한가요?`,
|
||||
a: `네, 시험 3~4주 전 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${props.regionDong} ${props.grade} ${props.subjectName} 과외 단기 속성 킬러 클리닉 프로그램도 상시 운영 중입니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.subjectName} 외에 다른 과목도 함께 상담받을 수 있나요?`,
|
||||
a: `${props.subjectName} 집중 신청은 물론, 국영수 또는 수탐 복합 패키지로 맞춤 구성하여 전 과목 플래너 관리와 함께 시간표를 편성하실 수 있습니다.`
|
||||
q: `${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외 외에 다른 과목도 함께 상담받을 수 있나요?`,
|
||||
a: `${props.subjectName} 집중 신청은 물론, 국영수 또는 수탐 복합 ${props.shortSido} ${props.gradeShort} 과외 패키지로 맞춤 구성하여 전 과목 플래너 관리와 함께 시간표를 편성하실 수 있습니다.`
|
||||
}
|
||||
])
|
||||
</script>
|
||||
@@ -146,6 +143,11 @@ const faqs = computed(() => [
|
||||
font-size: clamp(0.9rem, 2.2vw, 1.02rem);
|
||||
font-weight: 800;
|
||||
color: var(--text-color, #0f172a);
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.faq-question::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.q-icon {
|
||||
@@ -172,6 +174,11 @@ const faqs = computed(() => [
|
||||
font-size: 0.8rem;
|
||||
color: #94a3b8;
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
details[open] .toggle-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.faq-answer {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="focus-header">
|
||||
<span class="focus-badge">{{ isElementary ? '초등 맞춤 집중 케어' : `${displayGrade} 실전 시험 케어` }}</span>
|
||||
<h2 class="focus-main-title">
|
||||
{{ regionDong }} {{ displayGrade }} {{ displaySubject }}과외
|
||||
{{ shortSido ? `${shortSido} ` : '' }}{{ regionDong }} {{ displayGrade }} {{ displaySubject }}과외
|
||||
<span class="text-accent">5대 핵심 솔루션</span>
|
||||
</h2>
|
||||
<p class="focus-sub-desc">
|
||||
@@ -12,7 +12,7 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 네이버 5개 멀티 썸네일 스니펫 및 상담 링크 매칭용 5개 리스트 -->
|
||||
<!-- 네이버 5개 멀티 썸네일 스니펫 및 상담 링크 매칭용 가로 5열 캐러셀 -->
|
||||
<div class="focus-grid">
|
||||
<a
|
||||
v-for="(item, idx) in programList"
|
||||
@@ -21,27 +21,30 @@
|
||||
class="focus-card"
|
||||
:title="`${item.title} 상담 신청`"
|
||||
>
|
||||
<div class="focus-thumb-wrap">
|
||||
<img
|
||||
:src="item.image"
|
||||
:alt="`${item.title} 1:1 맞춤 지도`"
|
||||
width="500"
|
||||
height="500"
|
||||
loading="lazy"
|
||||
class="focus-img"
|
||||
/>
|
||||
<span class="step-tag">STEP 0{{ idx + 1 }}</span>
|
||||
</div>
|
||||
|
||||
<div class="focus-info">
|
||||
<div class="focus-item-tag">{{ item.tag }}</div>
|
||||
<strong class="focus-item-title">{{ item.title }}</strong>
|
||||
<p class="focus-item-desc">{{ item.desc }}</p>
|
||||
<div class="focus-cta-link">
|
||||
<span>1:1 상담 예약</span>
|
||||
<span class="arrow-sym">→</span>
|
||||
<figure class="focus-figure m-0 flex flex-col flex-1">
|
||||
<div class="focus-thumb-wrap">
|
||||
<img
|
||||
:src="item.image"
|
||||
:alt="item.title"
|
||||
width="1080"
|
||||
height="1080"
|
||||
decoding="async"
|
||||
loading="eager"
|
||||
fetchpriority="high"
|
||||
class="focus-img"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<figcaption class="focus-info">
|
||||
<div class="focus-item-tag">{{ item.tag }}</div>
|
||||
<h3 class="focus-item-title m-0">{{ item.title }}</h3>
|
||||
<p class="focus-item-desc">{{ item.desc }}</p>
|
||||
<div class="focus-cta-link">
|
||||
<span>1:1 상담 예약</span>
|
||||
<span class="arrow-sym">→</span>
|
||||
</div>
|
||||
</figcaption>
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -56,6 +59,14 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: '중등'
|
||||
},
|
||||
shortSido: {
|
||||
type: String,
|
||||
default: '대구'
|
||||
},
|
||||
subjectName: {
|
||||
type: String,
|
||||
default: '수학'
|
||||
@@ -78,7 +89,7 @@ const displaySubject = computed(() => {
|
||||
return props.subjectName || '수학'
|
||||
})
|
||||
|
||||
// 초등 vs 중등/고등 5개 항목 분기
|
||||
// 초등 vs 중등/고등 5개 항목 분기 (네이버 썸네일 추출 가능한 고해상도 실사 .png 5종 적용)
|
||||
const programList = computed(() => {
|
||||
const dong = props.regionDong ? `${props.regionDong} ` : ''
|
||||
const sub = displaySubject.value
|
||||
@@ -90,31 +101,31 @@ const programList = computed(() => {
|
||||
tag: '개념 완성',
|
||||
title: `${dong}초등 ${sub}과외 - 기초학습`,
|
||||
desc: '개념 쏙쏙 이해와 튼튼한 연산 기본기 완성',
|
||||
image: '/images/focus/elem-1-basic.svg'
|
||||
image: '/img/math-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '학습 코칭',
|
||||
title: `${dong}초등 ${sub}과외 - 공부방법`,
|
||||
desc: '스스로 원리를 깨우치는 올바른 문제 해결력',
|
||||
image: '/images/focus/elem-2-method.svg'
|
||||
image: '/img/english-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '밀착 피드백',
|
||||
title: `${dong}초등 ${sub}과외 - 숙제검사`,
|
||||
desc: '매일 1:1 오답 점검과 꼼꼼한 피드백 클리닉',
|
||||
image: '/images/focus/elem-3-homework.svg'
|
||||
image: '/img/korean-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '자기주도',
|
||||
title: `${dong}초등 ${sub}과외 - 공부습관`,
|
||||
desc: '매일 스스로 책상에 앉는 주도적 학습 루틴',
|
||||
image: '/images/focus/elem-4-habit.svg'
|
||||
image: '/img/science-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '상위권 도약',
|
||||
title: `${dong}초등 ${sub}과외 - 중등대비`,
|
||||
desc: '중학교 내신 서술형과 심화 개념 선행 마스터',
|
||||
image: '/images/focus/elem-5-middleprep.svg'
|
||||
image: '/img/social-studies-tutoring.png'
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -125,31 +136,31 @@ const programList = computed(() => {
|
||||
tag: '기출 정복',
|
||||
title: `${dong}${grd} 중간고사 ${sub}과외`,
|
||||
desc: '학교별 기출 족보 완벽 분석 및 서술형 킬러 대비',
|
||||
image: '/images/focus/sec-1-midterm.svg'
|
||||
image: '/img/math-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '학기말 총력',
|
||||
title: `${dong}${grd} 기말고사 ${sub}과외`,
|
||||
desc: '전 범위 오답 분석 및 취약 유형 완벽 클리닉',
|
||||
image: '/images/focus/sec-2-final.svg'
|
||||
image: '/img/english-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '수능·전국연합',
|
||||
title: `${dong}${grd} 모의고사 ${sub}과외`,
|
||||
desc: '수능형 사고력 확장 및 실전 시간 배분 특훈',
|
||||
image: '/images/focus/sec-3-mock.svg'
|
||||
image: '/img/korean-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '내신 만점',
|
||||
title: `${dong}${grd} 수행평가 ${sub}과외`,
|
||||
desc: '조건 감점 0점화 및 과제·보고서 완벽 케어',
|
||||
image: '/images/focus/sec-4-assessment.svg'
|
||||
image: '/img/science-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '1등급 집중',
|
||||
title: `${dong}${grd} 내신대비 ${sub}과외`,
|
||||
desc: '관내 교과서·부교재 적중 1:1 맞춤 지도',
|
||||
image: '/images/focus/sec-5-schoolprep.svg'
|
||||
image: '/img/social-studies-tutoring.png'
|
||||
}
|
||||
]
|
||||
})
|
||||
@@ -202,10 +213,10 @@ const programList = computed(() => {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 5열 카드 그리드 */
|
||||
/* 가로 1열 5칸 캐러셀 그리드 */
|
||||
.focus-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
grid-template-columns: repeat(5, minmax(180px, 1fr));
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
@@ -234,6 +245,7 @@ const programList = computed(() => {
|
||||
aspect-ratio: 1 / 1;
|
||||
background: #f1f5f9;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.focus-img {
|
||||
@@ -248,20 +260,6 @@ const programList = computed(() => {
|
||||
transform: scale(1.04);
|
||||
}
|
||||
|
||||
.step-tag {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
padding: 2px 8px;
|
||||
background: rgba(0, 0, 0, 0.55);
|
||||
backdrop-filter: blur(4px);
|
||||
color: #ffffff;
|
||||
font-size: 0.68rem;
|
||||
font-weight: 800;
|
||||
border-radius: 4px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.focus-info {
|
||||
padding: 14px 12px;
|
||||
display: flex;
|
||||
@@ -281,7 +279,7 @@ const programList = computed(() => {
|
||||
font-weight: 800;
|
||||
color: #0f172a;
|
||||
line-height: 1.35;
|
||||
margin-bottom: 6px;
|
||||
margin: 0 0 6px 0;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
@@ -313,52 +311,37 @@ const programList = computed(() => {
|
||||
transform: translateX(3px);
|
||||
}
|
||||
|
||||
/* 태블릿 및 모바일 반응형 */
|
||||
@media (max-width: 960px) {
|
||||
/* 태블릿 및 모바일 가로 스크롤 캐러셀 반응형 */
|
||||
@media (max-width: 1024px) {
|
||||
.focus-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.focus-grid {
|
||||
grid-template-columns: 1fr;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x mandatory;
|
||||
gap: 12px;
|
||||
padding-bottom: 12px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.focus-card {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex: 0 0 210px;
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.focus-grid {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x mandatory;
|
||||
gap: 12px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.focus-thumb-wrap {
|
||||
width: 105px;
|
||||
height: 105px;
|
||||
aspect-ratio: 1 / 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.focus-info {
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.focus-item-title {
|
||||
font-size: 0.88rem;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.focus-item-desc {
|
||||
font-size: 0.74rem;
|
||||
margin-bottom: 6px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.focus-cta-link {
|
||||
padding-top: 4px;
|
||||
font-size: 0.72rem;
|
||||
.focus-card {
|
||||
flex: 0 0 200px;
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<header class="hero-banner-clean bg-white border-b border-slate-200/80 pt-10 sm:pt-14 pb-14 sm:pb-18 px-4 sm:px-6 relative overflow-hidden text-center">
|
||||
<section class="hero-banner hero-banner-clean bg-white border-b border-slate-200/80 pt-10 sm:pt-14 pb-14 sm:pb-18 px-4 sm:px-6 relative overflow-hidden text-center" itemscope itemtype="https://schema.org/Course">
|
||||
|
||||
<!-- 은은한 상단 엠비언트 라이트 -->
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-blue-50/40 via-transparent to-transparent pointer-events-none"></div>
|
||||
@@ -12,16 +12,23 @@
|
||||
<span>{{ region.dong }} 학군 전담 | 서울대·연고대 및 베테랑 강사진 100% 신원 보증</span>
|
||||
</div>
|
||||
|
||||
<!-- SEO 메인 H1 (사용자 지정 롱테일 조합형: [지역] + [학년] + [과목]과외 + 검증된 전문 선생님 100% 매칭) -->
|
||||
<h1 class="text-2xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.22] sm:leading-[1.18] mb-4">
|
||||
<span>{{ displayRegionName }} {{ grade }} {{ subjectName }}과외</span><br />
|
||||
<span class="text-blue-600">우리 아이 맞춤 검증된 전문 선생님 100% 매칭</span>
|
||||
<!-- 1. H1 -->
|
||||
<h1 itemprop="headline" class="text-2xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.22] sm:leading-[1.18] mb-3">
|
||||
<span class="highlight text-blue-600">{{ shortSidoName }} {{ gradeShortName }} {{ subjectName }} 과외 · {{ region.dong }} {{ grade }} {{ subjectName }}과외</span><br />
|
||||
1:1 맞춤 학습으로 성적 역전!
|
||||
</h1>
|
||||
|
||||
<!-- 서브 카피 (비용 시세 비교 + 학교 기출 분석 + 무료 시범수업 신뢰 트리거) -->
|
||||
<p class="text-xs sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-7">
|
||||
{{ region.dong }} 인근 학교별 기출 분석부터 과외 비용·시세 비교, 취약 개념 클리닉까지.<br class="hidden sm:inline" />
|
||||
직접 수업받아보고 결정하는 <strong>1:1 무료 방문·화상 시범수업</strong>을 신청하세요.
|
||||
<!-- 2. meta (H1 바로 다음 줄) -->
|
||||
<meta itemprop="name" :content="`${shortSidoName} ${gradeShortName} ${subjectName} 과외 · ${shortSidoName} ${gradeShortName} 과외 (${region.dong})`" />
|
||||
<meta itemprop="description" :content="`${shortSidoName} ${gradeShortName} ${subjectName} 과외 및 ${shortSidoName} ${gradeShortName} 과외 전문 매칭. ${displayRegionName} ${grade} ${subjectName} 1:1 방문·화상 맞춤 수업`" />
|
||||
<meta itemprop="keywords" :content="`${shortSidoName} ${gradeShortName} ${subjectName} 과외, ${shortSidoName} ${gradeShortName} 과외, ${region.dong} ${gradeShortName} ${subjectName} 과외, ${region.dong} ${gradeShortName} 과외, ${displayRegionName} ${grade} ${subjectName}과외`" />
|
||||
<meta itemprop="image" content="/img/math-tutoring.png" />
|
||||
<!-- 3. H2 (meta 바로 다음 줄) -->
|
||||
<h2 class="hero-subtitle">
|
||||
{{ shortSidoName }} {{ gradeShortName }} 과외 · {{ displayRegionName }} {{ gradeShortName }} {{ subjectName }} 과외 검증된 전문 선생님 1:1 매칭
|
||||
</h2>
|
||||
<!-- 4. 일반글 p (H2 바로 다음 줄) -->
|
||||
<p class="sub-headline text-xs sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-7">
|
||||
{{ shortSidoName }} {{ gradeShortName }} {{ subjectName }} 과외 및 {{ shortSidoName }} {{ gradeShortName }} 과외를 찾으시는 학부모님을 위해 {{ region.dong }} 인근 학교별 기출 족보 분석부터 개인별 취약 개념 완벽 보완, 투명한 과외비 안내와 무료 시범수업까지 1:1 밀착 커리큘럼을 제공합니다.
|
||||
</p>
|
||||
|
||||
<!-- 4대 핵심 신뢰 지표 바 -->
|
||||
@@ -84,15 +91,15 @@
|
||||
|
||||
<!-- 태그 목록 -->
|
||||
<div class="flex justify-center flex-wrap gap-1.5">
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ shortSidoName }}{{ gradeShortName }}{{ subjectName }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ shortSidoName }}{{ gradeShortName }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ region.dong }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ region.dong }}{{ subjectName }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ grade }}내신대비</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#과외비용시세</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#1대1무료시범수업</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</header>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -111,12 +118,24 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
subjectName: {
|
||||
type: String,
|
||||
default: '수학'
|
||||
}
|
||||
})
|
||||
|
||||
const shortSidoName = computed(() => {
|
||||
return (props.region?.sido || '').replace(/특별시|광역시|특별자치시|도/g, '').trim()
|
||||
})
|
||||
|
||||
const gradeShortName = computed(() => {
|
||||
return props.gradeShort || (props.grade === '초등학생' ? '초등' : props.grade === '고등학생' ? '고등' : '중등')
|
||||
})
|
||||
|
||||
const noticeIdx = ref(0)
|
||||
let timer = null
|
||||
|
||||
@@ -171,4 +190,12 @@ const displayRegionName = computed(() => {
|
||||
.hero-banner-clean {
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-size: 1.15rem;
|
||||
font-weight: 700;
|
||||
color: #334155;
|
||||
margin-bottom: 0.75rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -116,15 +116,15 @@ const nearbyDongs = computed(() => {
|
||||
}
|
||||
|
||||
// 만약 동일 구의 동이 부족하면 전체에서 다른 동 가져오기
|
||||
if (candidates.length < 5) {
|
||||
if (candidates.length < 12) {
|
||||
const others = allList
|
||||
.filter(r => r.dong !== curDong && !candidates.includes(r.dong))
|
||||
.map(r => r.dong)
|
||||
candidates = [...candidates, ...others]
|
||||
}
|
||||
|
||||
// 중복 제거 후 6개 반환
|
||||
return Array.from(new Set(candidates)).slice(0, 6)
|
||||
// 중복 제거 후 12개 반환
|
||||
return Array.from(new Set(candidates)).slice(0, 12)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -3,30 +3,29 @@
|
||||
<!-- 1. 클린 미니멀 프리미엄 네비게이션 헤더 (기본 홈과 동일) -->
|
||||
<AppHeader :siteName="siteName" />
|
||||
|
||||
<!-- 2. 세련된 지역 센터 식별 서브 바 (모던 칩 배너) -->
|
||||
<div class="bg-blue-50/70 border-b border-blue-100/70 py-2.5 px-4">
|
||||
<!-- 2. 시맨틱 브레드크럼 네비게이션 바 (더세이브 nav.bc 구조 동기화) -->
|
||||
<nav class="bc bg-blue-50/70 border-b border-blue-100/70 py-2.5 px-4" aria-label="현재 위치">
|
||||
<div class="max-w-4xl mx-auto flex items-center justify-between flex-wrap gap-2 text-xs">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="inline-flex items-center gap-1 font-bold text-blue-700 bg-white px-2.5 py-0.5 rounded-full border border-blue-200/80 shadow-xs">
|
||||
<i class="fa-solid fa-location-dot text-blue-600 text-[10px]"></i>
|
||||
{{ parsed.shortRegionName }} 센터
|
||||
</span>
|
||||
<span class="text-slate-600 font-medium">
|
||||
{{ parsed.dong }} ({{ parsed.sigungu }}) 관내 초·중·고 1:1 맞춤 전담
|
||||
</span>
|
||||
<div class="flex items-center gap-1.5 text-slate-600 font-medium">
|
||||
<NuxtLink to="/" class="hover:text-blue-600 font-semibold transition-colors">홈</NuxtLink>
|
||||
<span class="text-slate-400">›</span>
|
||||
<span>{{ parsed.dong }} 과외</span>
|
||||
<span class="text-slate-400">›</span>
|
||||
<strong class="font-bold text-blue-700">{{ parsed.shortSido }} {{ parsed.gradeShort }} {{ parsed.subjectName }} 과외</strong>
|
||||
</div>
|
||||
<div class="hidden sm:flex items-center gap-1 text-slate-500 font-medium">
|
||||
<i class="fa-solid fa-shield-check text-emerald-600 text-xs"></i>
|
||||
<span>검증된 전문 선생님 100% 매칭</span>
|
||||
<span>{{ parsed.shortRegionName }} 센터 · 검증된 전문 선생님 100% 매칭</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- 3. 상단 히어로 배너 (H1 태그 포함) -->
|
||||
<!-- 3. 상단 히어로 배너 (H1 -> meta -> H2 -> p 순서) -->
|
||||
<HeroBanner
|
||||
:region="parsed.region"
|
||||
:shortRegionName="parsed.shortRegionName"
|
||||
:grade="parsed.grade"
|
||||
:grade-short="parsed.gradeShort"
|
||||
:subjectName="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -67,6 +66,8 @@
|
||||
<FaqAccordion
|
||||
:regionDong="parsed.dong"
|
||||
:grade="parsed.grade"
|
||||
:gradeShort="parsed.gradeShort"
|
||||
:shortSido="parsed.shortSido"
|
||||
:subjectName="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -74,6 +75,8 @@
|
||||
<FastConsultFocus
|
||||
:regionDong="parsed.dong"
|
||||
:grade="parsed.grade"
|
||||
:gradeShort="parsed.gradeShort"
|
||||
:shortSido="parsed.shortSido"
|
||||
:subjectName="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -81,6 +84,8 @@
|
||||
<SubjectCarousel
|
||||
:regionDong="parsed.dong"
|
||||
:grade="parsed.grade"
|
||||
:gradeShort="parsed.gradeShort"
|
||||
:shortSido="parsed.shortSido"
|
||||
:currentSubject="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -97,13 +102,11 @@
|
||||
:defaultGrade="parsed.grade"
|
||||
:defaultSubject="parsed.subjectName"
|
||||
/>
|
||||
|
||||
<!-- 14. 클린 사이트 푸터 -->
|
||||
<AppFooter />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { parseRouteSlug, getCurriculumBySubject, getAllSubjectsList, getPopularRegions } from '~/utils/dataHelper'
|
||||
import { generateSeoMeta } from '~/utils/seoHelper'
|
||||
@@ -112,28 +115,27 @@ const route = useRoute()
|
||||
const config = useRuntimeConfig()
|
||||
const siteName = config.public?.siteName || '티처브릿지'
|
||||
|
||||
// URL 파라미터 파싱
|
||||
const slug = route.params.slug
|
||||
const parsed = parseRouteSlug(slug)
|
||||
// URL 파라미터 파싱 (반응형 computed)
|
||||
const parsed = computed(() => parseRouteSlug(route.params.slug))
|
||||
|
||||
// 커리큘럼 데이터 로드
|
||||
const curriculum = getCurriculumBySubject(parsed.subjectKey)
|
||||
const curriculum = computed(() => getCurriculumBySubject(parsed.value.subjectKey))
|
||||
const allSubjects = getAllSubjectsList()
|
||||
const popularRegions = getPopularRegions(12)
|
||||
|
||||
// 네이버 Yeti 봇 100% 대응 SEO 메타태그 설정
|
||||
const seo = generateSeoMeta(
|
||||
parsed,
|
||||
const seo = computed(() => generateSeoMeta(
|
||||
parsed.value,
|
||||
config.public.siteName,
|
||||
config.public.siteDomain
|
||||
)
|
||||
))
|
||||
|
||||
useHead({
|
||||
title: seo.title,
|
||||
meta: seo.meta,
|
||||
link: seo.link,
|
||||
script: seo.script
|
||||
})
|
||||
useHead(() => ({
|
||||
title: seo.value.title,
|
||||
meta: seo.value.meta,
|
||||
link: seo.value.link,
|
||||
script: seo.value.script
|
||||
}))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<!-- 1. Header (클린 미니멀 프리미엄 네비게이션) -->
|
||||
<header class="bg-white/95 backdrop-blur-md border-b border-slate-200/80 sticky top-0 z-40 w-full transition-all">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6 py-3.5 flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<NuxtLink to="/" class="flex items-center gap-3">
|
||||
<div class="w-9 h-9 rounded-xl bg-blue-600 flex items-center justify-center text-white font-extrabold text-base shadow-sm">
|
||||
T
|
||||
{{ siteName.charAt(0) }}
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-extrabold text-lg sm:text-xl tracking-tight text-slate-900">{{ siteName }}</span>
|
||||
@@ -14,7 +14,7 @@
|
||||
교육청 등록 협력
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<a href="tel:010-5961-5807" class="hidden sm:flex items-center gap-1.5 text-sm font-semibold text-slate-600 hover:text-blue-600 transition">
|
||||
@@ -32,8 +32,8 @@
|
||||
<!-- 2. Main Body -->
|
||||
<main class="w-full pb-20">
|
||||
|
||||
<!-- 히어로 섹션 (AI 스타일 형광/물결 제거, 정제된 모던 에듀테크 캔버스) -->
|
||||
<section class="w-full bg-white border-b border-slate-200/80 pt-12 sm:pt-16 pb-20 px-4 sm:px-6 text-center relative overflow-hidden">
|
||||
<!-- 히어로 섹션 (H1 -> meta -> H2 -> p 순서) -->
|
||||
<section class="hero-section w-full bg-white border-b border-slate-200/80 pt-12 sm:pt-16 pb-20 px-4 sm:px-6 text-center relative overflow-hidden" itemscope itemtype="https://schema.org/EducationalOrganization">
|
||||
|
||||
<!-- 은은한 상단 엠비언트 라이트 (절제된 디자이너 톤) -->
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-blue-50/40 via-transparent to-transparent pointer-events-none"></div>
|
||||
@@ -46,16 +46,22 @@
|
||||
<span>수성구·달서구 등 대구 전지역 전담 | 서울대·경북대 및 베테랑 강사진 100% 신원 보증</span>
|
||||
</div>
|
||||
|
||||
<!-- 메인 H1 (지역 기반 검색 상위 노출 30자 규격 및 학부모 고의도 롱테일 키워드) -->
|
||||
<h1 class="text-3xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.2] sm:leading-[1.18] mb-4">
|
||||
대구 초·중·고 1:1 맞춤 과외 매칭<br class="hidden sm:inline" />
|
||||
<span class="text-blue-600">검증된 전문 선생님 100% 매칭</span>
|
||||
<!-- 1. 메인 H1 -->
|
||||
<h1 class="text-3xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.2] sm:leading-[1.18] mb-3">
|
||||
대구 중등 수학 과외 · 초·중·고 1:1 맞춤 과외 매칭<br class="hidden sm:inline" />
|
||||
<span class="text-blue-600">내신·수능 성적 향상의 시작</span>
|
||||
</h1>
|
||||
|
||||
<!-- 서브 헤드라인 (비용 시세 비교 + 수성구 등 학교 기출 분석 + 무료 시범수업) -->
|
||||
<p class="text-sm sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-8">
|
||||
과외 비용·시세 투명 비교부터 무료 시범수업 신청까지.<br class="hidden sm:inline" />
|
||||
수성구·달서구 등 대구 관내 학교별 기출 족보를 완벽 분석하여 <strong>내신 1등급 역전 솔루션</strong>을 제공합니다.
|
||||
<!-- 2. meta (H1 바로 다음 줄) -->
|
||||
<meta itemprop="name" :content="`${siteName} - 대구 중등 수학 과외 · 대구 중등 과외 1:1 매칭`" />
|
||||
<meta itemprop="description" content="대구 중등 수학 과외, 대구 중등 과외부터 초등·고등 국영수사과 1:1 방문·화상 맞춤 과외 매칭 및 과외비 투명 비교" />
|
||||
<meta itemprop="keywords" content="대구 중등 수학 과외, 대구 중등 과외, 대구 고등 수학 과외, 대구 고등 과외, 대구 초등 수학 과외, 대구 초등 과외, 대구 중등 영어 과외, 대구 과외, 범어동 과외" />
|
||||
<meta itemprop="image" :content="`${siteDomain}/img/math-tutoring.png`" />
|
||||
<link itemprop="url" :href="`${siteDomain}/`" />
|
||||
<!-- 3. H2 (meta 바로 다음 줄) -->
|
||||
<h2 class="hero-subtitle text-base sm:text-lg font-bold text-slate-700 mb-3">대구 중등 과외 · 초등·고등 국영수사과 검증된 전문 선생님 100% 1:1 매칭</h2>
|
||||
<!-- 4. 일반글 p (H2 바로 다음 줄) -->
|
||||
<p class="hero-desc text-sm sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-8">
|
||||
대구 중등 수학 과외 및 대구 중등 과외, 초등·고등 전 과목 과외 비용·시세 투명 비교부터 검증된 전문 선생님 무료 시범수업까지 학생에게 꼭 맞는 1:1 맞춤 수업을 제공합니다.
|
||||
</p>
|
||||
|
||||
<!-- 4대 핵심 신뢰 보증 지표 (Trust Bar) -->
|
||||
@@ -400,29 +406,32 @@
|
||||
</section>
|
||||
|
||||
<!-- 5. 과목별 1:1 맞춤과외 갤러리 캐러셀 (클릭 시 확대 모달 및 상담/이동) -->
|
||||
<SubjectCarousel grade="초·중·고" />
|
||||
<SubjectCarousel :regionDong="defaultDong" shortSido="대구" grade="중학생" gradeShort="중등" />
|
||||
|
||||
<!-- 6. FAQ 섹션 (정돈된 아코디언) -->
|
||||
<!-- 6. FAQ 섹션 (네이티브 details/summary 시맨틱 구조) -->
|
||||
<section class="mt-16 px-4 sm:px-6 max-w-4xl mx-auto">
|
||||
<header class="text-center mb-8">
|
||||
<span class="text-xs sm:text-sm font-bold text-slate-400 tracking-wider">FAQ</span>
|
||||
<h2 class="text-2xl sm:text-3xl font-extrabold text-slate-900 mt-1 tracking-tight">자주 묻는 질문</h2>
|
||||
<h2 class="text-2xl sm:text-3xl font-extrabold text-slate-900 mt-1 tracking-tight">대구 중등 수학 과외 · 대구 중등 과외 자주 묻는 질문</h2>
|
||||
<p class="text-xs sm:text-sm text-slate-500 mt-1">대구 학부모님들께서 가장 많이 문의하시는 과외 진행 절차입니다.</p>
|
||||
</header>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div v-for="(faq, idx) in faqs" :key="idx" class="border border-slate-200 rounded-xl overflow-hidden bg-white shadow-xs">
|
||||
<button @click="faq.open = !faq.open" class="w-full p-4 sm:p-5 text-left text-sm sm:text-base font-bold text-slate-800 flex justify-between items-center hover:bg-slate-50 transition">
|
||||
<details v-for="(faq, idx) in faqs" :key="idx" :open="idx === 0" class="qa border border-slate-200 rounded-xl overflow-hidden bg-white shadow-xs group">
|
||||
<summary class="w-full p-4 sm:p-5 text-left text-sm sm:text-base font-bold text-slate-800 cursor-pointer list-none flex justify-between items-center hover:bg-slate-50 transition">
|
||||
<span>{{ faq.q }}</span>
|
||||
<i class="fa-solid fa-chevron-down text-xs sm:text-sm text-slate-400 transition-transform" :class="{ 'rotate-180': faq.open }"></i>
|
||||
</button>
|
||||
<div v-show="faq.open" class="p-4 sm:p-5 pt-0 text-xs sm:text-sm text-slate-600 leading-relaxed border-t border-slate-100 bg-slate-50/50">
|
||||
<i class="fa-solid fa-chevron-down text-xs sm:text-sm text-slate-400 transition-transform group-open:rotate-180"></i>
|
||||
</summary>
|
||||
<div class="ans p-4 sm:p-5 pt-3 text-xs sm:text-sm text-slate-600 leading-relaxed border-t border-slate-100 bg-slate-50/50">
|
||||
{{ faq.a }}
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 7. 관내 학년·과목·지역별 내부 연계 허브 (SSR SEO 크롤링 최적화) -->
|
||||
<InternalLinkHub :regionDong="defaultDong" grade="중학생" subjectName="수학" />
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
@@ -434,6 +443,7 @@ import { ref, reactive, computed, onMounted } from 'vue'
|
||||
const config = useRuntimeConfig()
|
||||
const siteName = config.public.siteName || '티처브릿지'
|
||||
const siteDomain = config.public.siteDomain || 'https://soohyun.store'
|
||||
const defaultDong = '범어동'
|
||||
|
||||
const isSubmitting = ref(false)
|
||||
const submitSuccess = ref(false)
|
||||
@@ -548,23 +558,23 @@ function formatPhone(e) {
|
||||
|
||||
const faqs = reactive([
|
||||
{
|
||||
q: '무료 시범수업은 어떻게 진행되나요?',
|
||||
a: '신청서 접수 후 대구 전담 매니저가 유선으로 학생의 성향과 목표를 파악한 뒤, 가장 적합한 전문 선생님을 배정해 드립니다. 배정된 선생님이 1:1 방문 또는 화상으로 40~50분간 모의 수업 및 취약점 진단을 무료로 진행하며, 수업 후 계속 진행 여부를 편안하게 결정하실 수 있습니다.',
|
||||
q: '대구 중등 수학 과외 · 대구 중등 과외 무료 시범수업은 어떻게 진행되나요?',
|
||||
a: '대구 중등 수학 과외 및 대구 중등 과외 신청서 접수 후 대구 전담 매니저가 유선으로 학생의 성향과 목표를 파악한 뒤 가장 적합한 대구 초·중·고 과외 전문 선생님을 배정해 드립니다. 배정된 선생님이 1:1 방문 또는 화상으로 40~50분간 모의 수업 및 취약점 진단을 무료로 진행하며, 수업 후 계속 진행 여부를 편안하게 결정하실 수 있습니다.',
|
||||
open: true
|
||||
},
|
||||
{
|
||||
q: '과외 비용 및 시세는 어떻게 되나요?',
|
||||
a: '학년(초등/중등/고등)과 주당 수업 횟수(주 1회, 주 2회 등), 수업 시간(회당 60분~120분)에 따라 교육청 가이드라인에 맞춘 투명한 표준 시세로 책정됩니다. 상담 시 거품 없는 정확한 대구 우리 동네 과외 비용을 안내해 드립니다.',
|
||||
q: '대구 중등 수학 과외 및 대구 초·중·고 과외 비용·시세는 어떻게 되나요?',
|
||||
a: '대구 중등 수학 과외, 대구 중등 과외, 대구 초·중·고 과외 비용은 학년(초등/중등/고등)과 주당 수업 횟수(주 1회, 주 2회 등), 수업 시간(회당 60분~120분)에 따라 교육청 가이드라인에 맞춘 투명한 표준 시세로 책정됩니다. 상담 시 거품 없는 정확한 대구 우리 동네 과외 비용을 안내해 드립니다.',
|
||||
open: false
|
||||
},
|
||||
{
|
||||
q: '선생님 신원과 학력 검증은 어떻게 이루어지나요?',
|
||||
a: '모든 강사진은 주민등록초본, 대학/대학원 재학 및 졸업증명서, 성범죄 경력 조회 등 엄격한 4단계 서류 검증과 교육청 개인과외교습자 신고를 100% 완료한 검증된 전문 선생님입니다.',
|
||||
q: '대구 중등 과외 · 대구 초·중·고 과외 선생님 신원과 학력 검증은 어떻게 이루어지나요?',
|
||||
a: '대구 중등 수학 과외 및 대구 중등 과외 모든 강사진은 주민등록초본, 대학/대학원 재학 및 졸업증명서, 성범죄 경력 조회 등 엄격한 4단계 서류 검증과 교육청 개인과외교습자 신고를 100% 완료한 검증된 대구 초·중·고 과외 전문 선생님입니다.',
|
||||
open: false
|
||||
},
|
||||
{
|
||||
q: '선생님이 아이와 맞지 않으면 어떻게 하나요?',
|
||||
a: '무료 시범수업을 통해 사전에 호흡을 맞출 수 있으며, 정규 수업 진행 중에도 선생님 교체를 희망하시면 추가 비용 없이 100% 만족하실 때까지 새로운 선생님으로 무료 재매칭을 진행해 드립니다.',
|
||||
q: '대구 중등 수학 과외 선생님이 아이와 맞지 않으면 교체가 가능한가요?',
|
||||
a: '대구 중등 수학 과외 및 대구 중등 과외는 무료 시범수업을 통해 사전에 호흡을 맞출 수 있으며, 대구 초·중·고 과외 정규 수업 진행 중에도 선생님 교체를 희망하시면 추가 비용 없이 100% 만족하실 때까지 새로운 선생님으로 무료 재매칭을 진행해 드립니다.',
|
||||
open: false
|
||||
}
|
||||
])
|
||||
@@ -608,47 +618,89 @@ async function handleSubmit() {
|
||||
// SEO 태그 설정 (지역 기반 + 고의도 롱테일 키워드 30~35자 내외 글자 수 준수)
|
||||
// SEO 태그 및 소셜 메타데이터 (네이버/구글 검색 최적화 및 3종 구조화 데이터 JSON-LD)
|
||||
useHead({
|
||||
title: '과외매칭센터 | 대구 초·중·고 검증된 맞춤 과외 매칭',
|
||||
title: `대구 중등 수학 과외 · 대구 중등 과외 | 초·중·고 1:1 맞춤 과외 ${siteName}`,
|
||||
link: [
|
||||
{ rel: 'canonical', href: 'https://soohyun.store/' }
|
||||
],
|
||||
meta: [
|
||||
{ name: 'robots', content: 'index,follow' },
|
||||
{ name: 'naver-site-verification', content: 'dfb36e971115b72176e1c1e37c6ca27a95e855e3' },
|
||||
{ name: 'google-site-verification', content: 'DvXzTXFe_DBt8nrIiI7SwWYgOENNAWNW5op79syf5pM' },
|
||||
{ name: 'description', content: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 명문대 및 베테랑 전문 강사진 1:1 맞춤 배정 솔루션' },
|
||||
{ name: 'description', content: `대구 중등 수학 과외, 대구 중등 과외, 범어동 중등 수학 과외 전문 ${siteName}! 대구 초·중·고 국영수사과 1:1 방문·화상 맞춤 수업, 과외 비용·시세 투명 비교부터 무료 시범수업 신청까지.` },
|
||||
{ name: 'keywords', content: '대구 중등 수학 과외, 대구 중등 과외, 대구 고등 수학 과외, 대구 고등 과외, 대구 초등 수학 과외, 대구 초등 과외, 대구 중등 영어 과외, 대구 고등 영어 과외, 대구 과외, 범어동 과외, 범어동 중등 수학 과외' },
|
||||
{ property: 'og:type', content: 'website' },
|
||||
{ property: 'og:site_name', content: '과외매칭센터' },
|
||||
{ property: 'og:title', content: '과외매칭센터 | 대구 초·중·고 맞춤 과외 매칭' },
|
||||
{ property: 'og:description', content: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 검증된 전문 선생님 100% 매칭' },
|
||||
{ property: 'og:locale', content: 'ko_KR' },
|
||||
{ property: 'og:site_name', content: siteName },
|
||||
{ property: 'og:title', content: `대구 중등 수학 과외 · 대구 중등 과외 | 초·중·고 1:1 맞춤 과외 ${siteName}` },
|
||||
{ property: 'og:description', content: `대구 중등 수학 과외, 대구 중등 과외, 범어동 중등 수학 과외 전문 ${siteName}! 과외 비용·시세 투명 비교부터 무료 시범수업 신청까지 검증된 전문 선생님 100% 매칭` },
|
||||
{ property: 'og:url', content: 'https://soohyun.store/' },
|
||||
{ property: 'og:image', content: 'https://soohyun.store/img/og-main.png' },
|
||||
{ property: 'og:image:type', content: 'image/png' },
|
||||
{ property: 'og:image:width', content: '1200' },
|
||||
{ property: 'og:image:height', content: '630' },
|
||||
{ property: 'og:image:alt', content: '대구 중등 수학 과외 · 대구 중등 과외' },
|
||||
{ name: 'twitter:card', content: 'summary_large_image' },
|
||||
{ name: 'twitter:title', content: '과외매칭센터 | 대구 초·중·고 맞춤 과외 매칭' },
|
||||
{ name: 'twitter:description', content: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 검증된 전문 선생님 100% 매칭' },
|
||||
{ name: 'twitter:title', content: `대구 중등 수학 과외 · 대구 중등 과외 | 초·중·고 1:1 맞춤 과외 ${siteName}` },
|
||||
{ name: 'twitter:description', content: `대구 중등 수학 과외, 대구 중등 과외, 범어동 중등 수학 과외 전문 ${siteName}! 과외 비용·시세 투명 비교부터 무료 시범수업 신청까지 검증된 전문 선생님 100% 매칭` },
|
||||
{ name: 'twitter:image', content: 'https://soohyun.store/img/og-main.png' }
|
||||
],
|
||||
script: [
|
||||
// 1. EducationalOrganization / LocalBusiness 스키마
|
||||
// 1. @graph (WebSite + WebPage + ImageObject + EducationalOrganization / LocalBusiness)
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': ['EducationalOrganization', 'LocalBusiness'],
|
||||
name: '과외매칭센터',
|
||||
telephone: '+82-10-5961-5807',
|
||||
url: 'https://soohyun.store/',
|
||||
image: 'https://soohyun.store/img/og-main.png',
|
||||
address: {
|
||||
'@type': 'PostalAddress',
|
||||
streetAddress: '달구벌대로 2435 범어타워 4층',
|
||||
addressLocality: '수성구',
|
||||
addressRegion: '대구광역시',
|
||||
addressCountry: 'KR'
|
||||
},
|
||||
description: '대구 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관',
|
||||
areaServed: '대구광역시 전지역'
|
||||
'@graph': [
|
||||
{
|
||||
'@type': 'WebSite',
|
||||
'@id': `${siteDomain}/#site`,
|
||||
url: `${siteDomain}/`,
|
||||
name: siteName,
|
||||
inLanguage: 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'WebPage',
|
||||
'@id': `${siteDomain}/#page`,
|
||||
url: `${siteDomain}/`,
|
||||
name: `대구 중등 수학 과외 · 대구 중등 과외 | 초·중·고 1:1 맞춤 과외 ${siteName}`,
|
||||
description: `대구 중등 수학 과외, 대구 중등 과외, 범어동 중등 수학 과외 전문 ${siteName}! 대구 초·중·고 국영수사과 1:1 방문·화상 맞춤 수업`,
|
||||
isPartOf: { '@id': `${siteDomain}/#site` },
|
||||
primaryImageOfPage: { '@id': `${siteDomain}/#img` },
|
||||
inLanguage: 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'ImageObject',
|
||||
'@id': `${siteDomain}/#img`,
|
||||
url: `${siteDomain}/img/math-tutoring.png`,
|
||||
contentUrl: `${siteDomain}/img/math-tutoring.png`,
|
||||
width: 1080,
|
||||
height: 1080,
|
||||
caption: '대구 중등 수학 과외 · 대구 중등 과외'
|
||||
},
|
||||
{
|
||||
'@type': ['EducationalOrganization', 'LocalBusiness'],
|
||||
name: siteName,
|
||||
telephone: '+82-10-5961-5807',
|
||||
url: `${siteDomain}/`,
|
||||
image: [
|
||||
`${siteDomain}/img/og-main.png`,
|
||||
`${siteDomain}/img/math-tutoring.png`,
|
||||
`${siteDomain}/img/english-tutoring.png`,
|
||||
`${siteDomain}/img/korean-tutoring.png`,
|
||||
`${siteDomain}/img/science-tutoring.png`,
|
||||
`${siteDomain}/img/social-studies-tutoring.png`
|
||||
],
|
||||
address: {
|
||||
'@type': 'PostalAddress',
|
||||
streetAddress: '달구벌대로 2435 범어타워 4층',
|
||||
addressLocality: '수성구',
|
||||
addressRegion: '대구광역시',
|
||||
addressCountry: 'KR'
|
||||
},
|
||||
description: '대구 중등 수학 과외, 대구 중등 과외 및 대구 초·중·고 1:1 맞춤 과외 전문 교육 기관',
|
||||
areaServed: '대구광역시 전지역'
|
||||
}
|
||||
]
|
||||
})
|
||||
},
|
||||
// 2. FAQPage 스키마
|
||||
@@ -667,50 +719,56 @@ useHead({
|
||||
}))
|
||||
})
|
||||
},
|
||||
// 3. ItemList 과목별 갤러리 섹션 스키마
|
||||
// 3. ItemList 과목별 및 학년별 갤러리 섹션 스키마 (더세이브 최상위 name/url/image + Google Course 리치 결과)
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'ItemList',
|
||||
name: '과목별 1:1 맞춤 과외 프로그램',
|
||||
name: `대구 중등 수학 과외 · 대구 중등 과외 프로그램`,
|
||||
itemListElement: [
|
||||
{
|
||||
{ sub: '수학', grade: '중학생', title: '대구 중등 수학 과외 · 범어동 중학생 수학과외', desc: '개념 구멍 추적 및 킬러 문항 1:1 완파', img: 'math-tutoring.png' },
|
||||
{ sub: '영어', grade: '중학생', title: '대구 중등 영어 과외 · 범어동 중학생 영어과외', desc: '교과서·부교재 전 지문 변형 및 서술형 영작', img: 'english-tutoring.png' },
|
||||
{ sub: '국어', grade: '중학생', title: '대구 중등 국어 과외 · 범어동 중학생 국어과외', desc: '비문학 독해 논리와 교과서 문학 1:1 정밀 분석', img: 'korean-tutoring.png' },
|
||||
{ sub: '과학', grade: '중학생', title: '대구 중등 과학 과외 · 범어동 중학생 과학과외', desc: '통합과학 원리 이해 및 물화생지 킬러 단원 정복', img: 'science-tutoring.png' },
|
||||
{ sub: '사회', grade: '중학생', title: '대구 중등 사회 과외 · 범어동 중학생 사회과외', desc: '통합사회·한국사 핵심 흐름 및 사탐 만점 전략', img: 'social-studies-tutoring.png' },
|
||||
{ sub: '수학', grade: '초등학생', title: '대구 초등 수학 과외 · 범어동 초등학생 수학과외', desc: '초등 기초 연산부터 중등 과정 개념 선행까지 1:1 맞춤 지도', img: 'math-tutoring.png' },
|
||||
{ sub: '수학', grade: '고등학생', title: '대구 고등 수학 과외 · 범어동 고등학생 수학과외', desc: '대구 관내 고교 기출 족보 분석 및 수능·내신 1등급 완파', img: 'math-tutoring.png' },
|
||||
{ sub: '영어', grade: '고등학생', title: '대구 고등 영어 과외 · 범어동 고등학생 영어과외', desc: '고등 내신 서술형 영작 첨삭 및 모의고사 1등급 구문 독해', img: 'english-tutoring.png' }
|
||||
].map((item, idx) => {
|
||||
const courseUrl = `${siteDomain}/${encodeURIComponent(defaultDong)}/${encodeURIComponent(item.grade)}/${encodeURIComponent(item.sub)}`
|
||||
const imgUrl = `${siteDomain}/img/${item.img}`
|
||||
return {
|
||||
'@type': 'ListItem',
|
||||
position: 1,
|
||||
name: '수학과외',
|
||||
description: '개념 구멍 추적 및 킬러 문항 1:1 완파',
|
||||
image: 'https://soohyun.store/img/math-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 2,
|
||||
name: '영어과외',
|
||||
description: '교과서·부교재 전 지문 변형 및 서술형 영작',
|
||||
image: 'https://soohyun.store/img/english-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 3,
|
||||
name: '국어과외',
|
||||
description: '비문학 독해 논리와 교과서 문학 1:1 정밀 분석',
|
||||
image: 'https://soohyun.store/img/korean-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 4,
|
||||
name: '과학과외',
|
||||
description: '통합과학 원리 이해 및 물화생지 킬러 단원 정복',
|
||||
image: 'https://soohyun.store/img/science-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 5,
|
||||
name: '사회과외',
|
||||
description: '통합사회·한국사 핵심 흐름 및 사탐 만점 전략',
|
||||
image: 'https://soohyun.store/img/social-studies-tutoring.png'
|
||||
position: idx + 1,
|
||||
name: item.title,
|
||||
url: courseUrl,
|
||||
image: imgUrl,
|
||||
item: {
|
||||
'@type': 'Course',
|
||||
name: item.title,
|
||||
description: item.desc,
|
||||
url: courseUrl,
|
||||
image: imgUrl,
|
||||
provider: {
|
||||
'@type': 'Organization',
|
||||
name: siteName,
|
||||
sameAs: siteDomain
|
||||
},
|
||||
offers: {
|
||||
'@type': 'Offer',
|
||||
category: 'Paid',
|
||||
priceCurrency: 'KRW',
|
||||
availability: 'https://schema.org/InStock',
|
||||
url: courseUrl
|
||||
},
|
||||
hasCourseInstance: {
|
||||
'@type': 'CourseInstance',
|
||||
courseMode: ['onsite', 'online']
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
</defs>
|
||||
<rect width="1200" height="630" fill="url(#bg)"/>
|
||||
<rect x="80" y="80" width="160" height="48" rx="8" fill="#fbbf24"/>
|
||||
<text x="160" y="112" font-family="'Pretendard', sans-serif" font-size="22" font-weight="900" fill="#1e293b" text-anchor="middle">AESEO</text>
|
||||
<text x="160" y="112" font-family="'Pretendard', sans-serif" font-size="22" font-weight="900" fill="#1e293b" text-anchor="middle">티처브릿지</text>
|
||||
<text x="80" y="240" font-family="'Pretendard', sans-serif" font-size="56" font-weight="900" fill="#ffffff">우리 동네 초·중·고 1:1 맞춤 과외</text>
|
||||
<text x="80" y="320" font-family="'Pretendard', sans-serif" font-size="68" font-weight="900" fill="#fbbf24">내신 1등급 전문 과외애서</text>
|
||||
<text x="80" y="320" font-family="'Pretendard', sans-serif" font-size="68" font-weight="900" fill="#fbbf24">내신 1등급 전문 티처브릿지</text>
|
||||
<text x="80" y="420" font-family="'Pretendard', sans-serif" font-size="30" font-weight="500" fill="#e0e7ff">국어 · 영어 · 수학 · 과학 · 사회 · 수행평가 세특</text>
|
||||
<text x="80" y="480" font-family="'Pretendard', sans-serif" font-size="28" font-weight="700" fill="#ffffff">전국 568개 동 학교별 기출 족보 완벽 분석</text>
|
||||
<rect x="80" y="530" width="340" height="50" rx="25" fill="#10b981"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -83,7 +83,7 @@
|
||||
|
||||
<!-- 성적 상승 그래프 비주얼 -->
|
||||
<text x="35" y="55" fill="#f8fafc" font-size="18" font-weight="800" font-family="'Pretendard', sans-serif">
|
||||
AESEO 성적 향상 지표
|
||||
티처브릿지 성적 향상 지표
|
||||
</text>
|
||||
<text x="35" y="80" fill="#94a3b8" font-size="13" font-family="'Pretendard', sans-serif">
|
||||
수강생 평균 2.3등급 수직 상승
|
||||
@@ -96,7 +96,7 @@
|
||||
<text x="32" y="55" fill="#94a3b8" font-size="13" font-weight="700" text-anchor="middle">4등급</text>
|
||||
<text x="32" y="185" fill="#94a3b8" font-size="12" text-anchor="middle">수강 전</text>
|
||||
|
||||
<!-- 과외애서 수강 후 바 -->
|
||||
<!-- 티처브릿지 수강 후 바 -->
|
||||
<rect x="95" y="10" width="75" height="150" rx="6" fill="url(#goldGrad)" />
|
||||
<text x="132" y="-5" fill="#f59e0b" font-size="16" font-weight="900" text-anchor="middle">1등급!</text>
|
||||
<text x="132" y="185" fill="#ffffff" font-size="13" font-weight="800" text-anchor="middle">수강 3개월</text>
|
||||
@@ -118,7 +118,7 @@
|
||||
|
||||
<!-- 우측 하단 워터마크 -->
|
||||
<text x="355" y="325" fill="#ffffff" opacity="0.3" font-size="13" font-weight="800" text-anchor="end" font-family="'Pretendard', sans-serif">
|
||||
AESEO TUTORING POSTER
|
||||
티처브릿지 TUTORING POSTER
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
@@ -1,26 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title><![CDATA[과외매칭센터]]></title>
|
||||
<title><![CDATA[티처브릿지]]></title>
|
||||
<link>https://soohyun.store/</link>
|
||||
<description><![CDATA[대구 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관]]></description>
|
||||
<language>ko</language>
|
||||
<pubDate>Tue, 20 Oct 2026 03:35:57 GMT</pubDate>
|
||||
<lastBuildDate>Tue, 20 Oct 2026 03:35:57 GMT</lastBuildDate>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<lastBuildDate>Wed, 04 Nov 2026 00:47:43 GMT</lastBuildDate>
|
||||
<atom:link href="https://soohyun.store/rss.xml" rel="self" type="application/rss+xml"/>
|
||||
<item>
|
||||
<title><![CDATA[대구 초·중·고 1:1 맞춤 과외 매칭]]></title>
|
||||
<link>https://soohyun.store/</link>
|
||||
<description><![CDATA[수성구 등 대구 전지역 과외 비용 비교 및 시범수업 신청]]></description>
|
||||
<pubDate>Tue, 20 Oct 2026 03:35:57 GMT</pubDate>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<guid>https://soohyun.store/</guid>
|
||||
</item>
|
||||
<item>
|
||||
<title><![CDATA[범어동 중학생 수학과외 1:1 맞춤 수업]]></title>
|
||||
<link>https://soohyun.store/%EB%B2%94%EC%96%B4%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</link>
|
||||
<description><![CDATA[수성구 학군 기출 족보 완파]]></description>
|
||||
<pubDate>Tue, 20 Oct 2026 03:35:57 GMT</pubDate>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<guid>https://soohyun.store/%EB%B2%94%EC%96%B4%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</guid>
|
||||
</item>
|
||||
<item>
|
||||
<title><![CDATA[황금동 고등학생 영어과외 1:1 맞춤 수업]]></title>
|
||||
<link>https://soohyun.store/%ED%99%A9%EA%B8%88%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</link>
|
||||
<description><![CDATA[수성구 황금동 내신 1등급 집중 코칭]]></description>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<guid>https://soohyun.store/%ED%99%A9%EA%B8%88%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</guid>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
|
||||
@@ -29,8 +29,8 @@ export default defineEventHandler(async (event) => {
|
||||
}
|
||||
|
||||
const webhookUrl = config.discordWebhookUrl || 'https://discordapp.com/api/webhooks/1557204310369116210/9J4y96kmSbYNGtw5OxRgIz7InWcM8o3f8UX0Ad71-IyofwdS7tWmXkF7dj457-I8Ypiu'
|
||||
const siteName = config.public.siteName || '1:1 맞춤과외'
|
||||
const siteDomain = config.public.siteDomain || 'https://aeseo.cloud'
|
||||
const siteName = config.public.siteName || '티처브릿지'
|
||||
const siteDomain = config.public.siteDomain || 'https://soohyun.store'
|
||||
|
||||
// 한국 시간 (KST)
|
||||
const now = new Date()
|
||||
@@ -53,7 +53,7 @@ export default defineEventHandler(async (event) => {
|
||||
{
|
||||
title: `[신규 무료 상담 신청 접수] ${finalLocation} - ${finalGrade} (${finalStudentName} 학생)`,
|
||||
description: `**${siteName}** 사이트에서 새로운 1:1 학습 상담 신청이 접수되었습니다.`,
|
||||
color: 0x991b1b, // 신뢰감 있는 딥 레드/네이비
|
||||
color: 0x991b1b,
|
||||
fields: [
|
||||
{
|
||||
name: "[접수 사이트]",
|
||||
|
||||
@@ -4,24 +4,42 @@ export default defineEventHandler((event) => {
|
||||
const config = useRuntimeConfig()
|
||||
const baseUrl = config.public.siteDomain || 'https://soohyun.store'
|
||||
const list = regionsData.list as Array<{ sido: string, sigungu: string, dong: string }>
|
||||
const today = new Date().toISOString().split('T')[0]
|
||||
|
||||
const subjects = ['영어', '수학', '국어', '통합과학', '통합사회']
|
||||
const grades = ['중학생', '고등학생']
|
||||
const subjects = ['수학', '영어', '국어', '과학', '사회']
|
||||
const grades = ['초등학생', '중학생', '고등학생']
|
||||
const subjectImages: Record<string, string> = {
|
||||
'수학': `${baseUrl}/img/math-tutoring.png`,
|
||||
'영어': `${baseUrl}/img/english-tutoring.png`,
|
||||
'국어': `${baseUrl}/img/korean-tutoring.png`,
|
||||
'과학': `${baseUrl}/img/science-tutoring.png`,
|
||||
'사회': `${baseUrl}/img/social-studies-tutoring.png`
|
||||
}
|
||||
|
||||
let xml = `<?xml version="1.0" encoding="UTF-8"?>\n`
|
||||
xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n`
|
||||
xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">\n`
|
||||
|
||||
// 메인
|
||||
xml += ` <url>\n <loc>${baseUrl}/</loc>\n <changefreq>daily</changefreq>\n <priority>1.0</priority>\n </url>\n`
|
||||
xml += ` <url>\n <loc>${baseUrl}/</loc>\n <lastmod>${today}</lastmod>\n <changefreq>daily</changefreq>\n <priority>1.0</priority>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/og-main.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/math-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/english-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/korean-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/science-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/social-studies-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` </url>\n`
|
||||
|
||||
// 568개 동별 주요 과목 및 학년 URL 생성
|
||||
// 동별 주요 과목 및 학년 URL 생성 (슬래시 라우터 구조 통일)
|
||||
list.forEach(r => {
|
||||
// 1. 동 대표
|
||||
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(r.dong)}</loc>\n <changefreq>weekly</changefreq>\n <priority>0.8</priority>\n </url>\n`
|
||||
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(r.dong)}</loc>\n <lastmod>${today}</lastmod>\n <changefreq>weekly</changefreq>\n <priority>0.8</priority>\n <image:image><image:loc>${baseUrl}/img/math-tutoring.png</image:loc></image:image>\n </url>\n`
|
||||
|
||||
// 2. 동-과목-학년 대표 조합
|
||||
subjects.slice(0, 3).forEach(sub => {
|
||||
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(r.dong)}-${encodeURIComponent(grades[0])}-${encodeURIComponent(sub)}</loc>\n <changefreq>weekly</changefreq>\n <priority>0.7</priority>\n </url>\n`
|
||||
// 2. 동/학년/과목 조합
|
||||
grades.forEach(g => {
|
||||
subjects.forEach(sub => {
|
||||
const imgLoc = subjectImages[sub] || `${baseUrl}/img/math-tutoring.png`
|
||||
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(r.dong)}/${encodeURIComponent(g)}/${encodeURIComponent(sub)}</loc>\n <lastmod>${today}</lastmod>\n <changefreq>weekly</changefreq>\n <priority>0.7</priority>\n <image:image><image:loc>${imgLoc}</image:loc></image:image>\n </url>\n`
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -17,10 +17,12 @@ export interface ParsedRouteParams {
|
||||
dong: string
|
||||
shortRegionName: string
|
||||
grade: string
|
||||
gradeShort: string
|
||||
subjectKey: string
|
||||
subjectName: string
|
||||
targetTerm: string
|
||||
fullKeyword: string
|
||||
isRegionOnly?: boolean
|
||||
}
|
||||
|
||||
// 5대 핵심 과목 정의
|
||||
@@ -34,30 +36,34 @@ export const SUBJECTS_MAP: Record<string, { key: string, name: string, badge: st
|
||||
|
||||
// 학년 정의
|
||||
export const GRADES_LIST = [
|
||||
{ key: 'middle', name: '중학생', aliases: ['중학생', '중1', '중2', '중3', '중등'] },
|
||||
{ key: 'high', name: '고등학생', aliases: ['고등학생', '고1', '고2', '고3', '고등', '예비고1'] },
|
||||
{ key: 'elem', name: '초등학생', aliases: ['초등학생', '초등', '초5', '초6'] }
|
||||
{ key: 'middle', name: '중학생', shortName: '중등', aliases: ['중학생', '중1', '중2', '중3', '중등'] },
|
||||
{ key: 'high', name: '고등학생', shortName: '고등', aliases: ['고등학생', '고1', '고2', '고3', '고등', '예비고1', 'N수', '재수'] },
|
||||
{ key: 'elem', name: '초등학생', shortName: '초등', aliases: ['초등학생', '초등', '초1', '초2', '초3', '초4', '초5', '초6'] }
|
||||
]
|
||||
|
||||
// 동 이름으로 지역 검색
|
||||
export function getRegionByDong(dongQuery: string): RegionInfo | null {
|
||||
if (!dongQuery) return null
|
||||
const clean = dongQuery.trim().replace(/동$/, '') // '황금' 또는 '황금동' 모두 매칭
|
||||
const clean = dongQuery.trim().replace(/[동읍면리가]$/, '')
|
||||
const map = regionsData.dongMap as Record<string, RegionInfo[]>
|
||||
|
||||
// 1. 정확 매칭 (황금동)
|
||||
// 1. 정확 매칭
|
||||
if (map[dongQuery] && map[dongQuery].length > 0) {
|
||||
return map[dongQuery][0]
|
||||
}
|
||||
// 2. '동' 붙여서 매칭
|
||||
if (map[dongQuery + '동'] && map[dongQuery + '동'].length > 0) {
|
||||
return map[dongQuery + '동'][0]
|
||||
// 2. '동', '읍', '면' 붙여서 매칭
|
||||
for (const suffix of ['동', '읍', '면']) {
|
||||
if (map[clean + suffix] && map[clean + suffix].length > 0) {
|
||||
return map[clean + suffix][0]
|
||||
}
|
||||
}
|
||||
// 3. 리스트 전체 순회 매칭
|
||||
const found = (regionsData.list as RegionInfo[]).find(r =>
|
||||
r.dong === dongQuery ||
|
||||
r.dong === (dongQuery + '동') ||
|
||||
r.dong.startsWith(clean)
|
||||
r.dong === (clean + '동') ||
|
||||
r.dong === (clean + '읍') ||
|
||||
r.dong === (clean + '면') ||
|
||||
(clean.length >= 2 && r.dong.startsWith(clean))
|
||||
)
|
||||
return found || null
|
||||
}
|
||||
@@ -99,12 +105,6 @@ export function getShortRegionName(sido: string, dong: string, sigungu?: string)
|
||||
}
|
||||
|
||||
// 지능형 URL 슬러그 파서
|
||||
// 지원 예시:
|
||||
// - ['대구광역시', '수성구', '황금동']
|
||||
// - ['대구광역시', '황금동', '중학생', '영어']
|
||||
// - ['황금동', '중학생', '영어']
|
||||
// - ['황금동-중학생-영어']
|
||||
// - '대구광역시-황금동-중학생-영어'
|
||||
export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams {
|
||||
let tokens: string[] = []
|
||||
|
||||
@@ -117,6 +117,7 @@ export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams
|
||||
|
||||
let matchedRegion: RegionInfo | null = null
|
||||
let detectedGrade = '중학생'
|
||||
let detectedGradeShort = '중등'
|
||||
let detectedSubjectKey = 'english'
|
||||
let detectedSubjectName = '영어'
|
||||
let detectedTerm = '과외'
|
||||
@@ -141,30 +142,37 @@ export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams
|
||||
}
|
||||
}
|
||||
|
||||
// 기본값 (568개 타겟 지역 중 첫 번째 기준)
|
||||
// 기본값 (타겟 지역 중 첫 번째 기준)
|
||||
if (!matchedRegion) {
|
||||
matchedRegion = (regionsData.list as RegionInfo[])[0] || {
|
||||
fullName: '경기도 고양시 덕양구 고양동',
|
||||
sido: '경기도',
|
||||
sigungu: '고양시 덕양구',
|
||||
dong: '고양동'
|
||||
fullName: '대구광역시 수성구 범어동',
|
||||
sido: '대구광역시',
|
||||
sigungu: '수성구',
|
||||
dong: '범어동'
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 학년 추출
|
||||
let hasExplicitGrade = false
|
||||
const fullText = tokens.join(' ')
|
||||
for (const g of GRADES_LIST) {
|
||||
if (g.aliases.some(a => fullText.includes(a))) {
|
||||
detectedGrade = g.name
|
||||
detectedGradeShort = g.shortName
|
||||
hasExplicitGrade = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const gradeShort = detectedGradeShort || (detectedGrade === '초등학생' ? '초등' : detectedGrade === '고등학생' ? '고등' : '중등')
|
||||
|
||||
// 4. 과목 추출
|
||||
let hasExplicitSubject = false
|
||||
for (const [key, sub] of Object.entries(SUBJECTS_MAP)) {
|
||||
if (sub.aliases.some(a => fullText.includes(a))) {
|
||||
detectedSubjectKey = key
|
||||
detectedSubjectName = sub.name
|
||||
hasExplicitSubject = true
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -188,10 +196,12 @@ export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams
|
||||
dong: matchedRegion.dong,
|
||||
shortRegionName,
|
||||
grade: detectedGrade,
|
||||
gradeShort,
|
||||
subjectKey: detectedSubjectKey,
|
||||
subjectName: detectedSubjectName,
|
||||
targetTerm: detectedTerm,
|
||||
fullKeyword
|
||||
fullKeyword,
|
||||
isRegionOnly: !hasExplicitGrade && !hasExplicitSubject
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,151 +1,315 @@
|
||||
import type { ParsedRouteParams } from './dataHelper'
|
||||
import type { ParsedRouteParams } from './dataHelper'
|
||||
import { getShortRegionName } from './dataHelper'
|
||||
|
||||
const SUBJECT_IMAGE_MAP: Record<string, string> = {
|
||||
math: '/img/math-tutoring.png',
|
||||
english: '/img/english-tutoring.png',
|
||||
korean: '/img/korean-tutoring.png',
|
||||
science: '/img/science-tutoring.png',
|
||||
social: '/img/social-studies-tutoring.png'
|
||||
}
|
||||
|
||||
const CORE_SUBJECTS = [
|
||||
{ key: 'math', name: '수학', desc: '개념 구멍 추적 및 킬러 문항 1:1 완파', img: '/img/math-tutoring.png' },
|
||||
{ key: 'english', name: '영어', desc: '교과서·부교재 전 지문 변형 및 서술형 영작', img: '/img/english-tutoring.png' },
|
||||
{ key: 'korean', name: '국어', desc: '비문학 독해 논리와 교과서 문학 1:1 정밀 분석', img: '/img/korean-tutoring.png' },
|
||||
{ key: 'science', name: '과학', desc: '통합과학 원리 이해 및 물화생지 킬러 단원 정복', img: '/img/science-tutoring.png' },
|
||||
{ key: 'social', name: '사회', desc: '통합사회·한국사 핵심 흐름 및 사탐 만점 전략', img: '/img/social-studies-tutoring.png' }
|
||||
]
|
||||
|
||||
const CORE_GRADES = ['초등학생', '중학생', '고등학생']
|
||||
|
||||
export function generateSeoMeta(parsed: ParsedRouteParams, siteName = '티처브릿지', siteDomain = 'https://soohyun.store') {
|
||||
const { sido, sigungu, dong, shortRegionName, grade, subjectName, targetTerm, fullKeyword } = parsed
|
||||
const { sido, sigungu, dong, shortRegionName, grade, subjectKey, subjectName, isRegionOnly } = parsed
|
||||
|
||||
const shortSido = parsed.shortSido || sido.replace(/특별시|광역시|특별자치시|도/g, '').trim()
|
||||
const gradeShort = parsed.gradeShort || (grade === '초등학생' ? '초등' : grade === '고등학생' ? '고등' : '중등')
|
||||
const regionTitle = shortRegionName || getShortRegionName(sido, dong)
|
||||
const subjectImg = SUBJECT_IMAGE_MAP[subjectKey] || '/img/math-tutoring.png'
|
||||
|
||||
// 학부모 검색 최적화: [지역] [과목]과외 전문 매칭 | [학년] 1:1 방문 맞춤 수업 (공백 포함 30~35자 내외 말줄임 방지)
|
||||
const pageTitle = `${regionTitle} ${subjectName}과외 전문 매칭 | ${grade} 1:1 방문 맞춤 수업`
|
||||
// 검색어 [지역] [초등/중등/고등] [과목] 과외 / [지역] [초등/중등/고등] 과외 완벽 매칭 타이틀
|
||||
const pageTitle = isRegionOnly
|
||||
? `${shortSido} 중등 수학 과외 · ${shortSido} 중등 과외 | ${regionTitle} 초·중·고 1:1 맞춤 과외`
|
||||
: `${shortSido} ${gradeShort} ${subjectName} 과외 · ${regionTitle} ${grade} ${subjectName}과외 | ${shortSido} ${gradeShort} 과외 1:1 매칭`
|
||||
|
||||
// 고의도 검색 및 전환 최적화 메타 디스크립션 (과외 비용 시세 + 학교 기출 분석 + 100% 신원 검증 + 무료 시범수업)
|
||||
const pageDescription = `${regionTitle} ${grade} ${subjectName}과외 전문 매칭. 과외 비용 및 시세 비교부터 무료 시범수업 신청까지. ${dong} 인근 학교별 기출 족보 완벽 분석, 서술형 감점 방지, 검증된 1:1 전문 선생님 100% 매칭.`
|
||||
// 첫 문장이 정확한 타겟 키워드로 시작하는 고의도 메타 디스크립션 (더세이브 동기화)
|
||||
const pageDescription = isRegionOnly
|
||||
? `${shortSido} 중등 수학 과외, ${shortSido} 중등 과외, ${dong} 중등 수학 과외 전문 ${siteName}! ${regionTitle} 초등·중등·고등 국영수사과 1:1 맞춤 과외, 검증된 전문 선생님 무료 시범수업과 과외비 비교를 확인하세요.`
|
||||
: `${shortSido} ${gradeShort} ${subjectName} 과외, ${shortSido} ${gradeShort} 과외, ${dong} ${gradeShort} ${subjectName} 과외 전문 ${siteName}! ${regionTitle} ${grade} ${subjectName} 1:1 방문·화상 맞춤 수업으로 내신·수능 성적 향상을 책임집니다. 과외비 투명 공개 및 무료 시범수업 신청하세요.`
|
||||
|
||||
// 표준 Canonical URL
|
||||
const canonicalUrl = `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(grade)}/${encodeURIComponent(subjectName)}`
|
||||
const pageKeywords = `${shortSido} ${gradeShort} ${subjectName} 과외, ${shortSido} ${gradeShort} 과외, ${dong} ${gradeShort} ${subjectName} 과외, ${dong} ${gradeShort} 과외, ${shortSido}${gradeShort}${subjectName}과외, ${shortSido}${gradeShort}과외, ${shortSido} 중등 수학 과외, ${shortSido} 중등 과외, ${shortSido} 고등 수학 과외, ${shortSido} 초등 수학 과외, ${regionTitle} ${subjectName}과외, ${dong} ${subjectName}과외, ${dong} ${grade} ${subjectName}과외, ${dong}과외, ${sigungu}과외, ${shortSido}과외`
|
||||
|
||||
const jsonLd = {
|
||||
// 표준 Canonical URL (자기참조 분리)
|
||||
const dongUrl = `${siteDomain}/${encodeURIComponent(dong)}`
|
||||
const canonicalUrl = isRegionOnly
|
||||
? dongUrl
|
||||
: `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(grade)}/${encodeURIComponent(subjectName)}`
|
||||
|
||||
// 더세이브 방식 멀티 이미지 배열
|
||||
const orgImages = [
|
||||
`${siteDomain}/img/og-main.png`,
|
||||
`${siteDomain}/img/math-tutoring.png`,
|
||||
`${siteDomain}/img/english-tutoring.png`,
|
||||
`${siteDomain}/img/korean-tutoring.png`,
|
||||
`${siteDomain}/img/science-tutoring.png`,
|
||||
`${siteDomain}/img/social-studies-tutoring.png`
|
||||
]
|
||||
|
||||
// 서브 라우터 캐러셀(ItemList) 항목 구성: 현재 동 기준 5대 과목 + 타 학년 라우터 (중복 제외 총 7개)
|
||||
const carouselCourses: Array<{ name: string, desc: string, url: string, image: string }> = []
|
||||
for (const sub of CORE_SUBJECTS) {
|
||||
const cUrl = `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(grade)}/${encodeURIComponent(sub.name)}`
|
||||
carouselCourses.push({
|
||||
name: `${shortSido} ${gradeShort} ${sub.name} 과외 · ${regionTitle} ${grade} ${sub.name}과외`,
|
||||
desc: `${dong} 관내 학교 내신 기출 분석 및 ${sub.desc}`,
|
||||
url: cUrl,
|
||||
image: `${siteDomain}${sub.img}`
|
||||
})
|
||||
}
|
||||
for (const g of CORE_GRADES) {
|
||||
if (g === grade) continue
|
||||
const gShort = g === '초등학생' ? '초등' : g === '고등학생' ? '고등' : '중등'
|
||||
const cUrl = `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(g)}/${encodeURIComponent(subjectName)}`
|
||||
carouselCourses.push({
|
||||
name: `${shortSido} ${gShort} ${subjectName} 과외 · ${regionTitle} ${g} ${subjectName}과외`,
|
||||
desc: `${dong} ${g} 학생 대상 ${subjectName} 내신·선행 1:1 밀착 지도`,
|
||||
url: cUrl,
|
||||
image: `${siteDomain}${subjectImg}`
|
||||
})
|
||||
}
|
||||
|
||||
const breadcrumbItems = isRegionOnly
|
||||
? [
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 1,
|
||||
'name': '홈',
|
||||
'item': `${siteDomain}/`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 2,
|
||||
'name': `${regionTitle} 과외`,
|
||||
'item': dongUrl
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 1,
|
||||
'name': '홈',
|
||||
'item': `${siteDomain}/`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 2,
|
||||
'name': `${dong} 과외`,
|
||||
'item': dongUrl
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 3,
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 · ${dong} ${grade} ${subjectName}과외`,
|
||||
'item': canonicalUrl
|
||||
}
|
||||
]
|
||||
|
||||
// 블록 1: @graph (WebSite + WebPage + ImageObject + EducationalOrganization + LocalBusiness + Course + BreadcrumbList)
|
||||
const graphJsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@graph': [
|
||||
{
|
||||
'@type': 'WebSite',
|
||||
'@id': `${siteDomain}/#site`,
|
||||
'url': `${siteDomain}/`,
|
||||
'name': siteName,
|
||||
'inLanguage': 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'WebPage',
|
||||
'@id': `${canonicalUrl}#page`,
|
||||
'url': canonicalUrl,
|
||||
'name': pageTitle,
|
||||
'description': pageDescription,
|
||||
'isPartOf': { '@id': `${siteDomain}/#site` },
|
||||
'primaryImageOfPage': { '@id': `${canonicalUrl}#img` },
|
||||
'inLanguage': 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'ImageObject',
|
||||
'@id': `${canonicalUrl}#img`,
|
||||
'url': `${siteDomain}${subjectImg}`,
|
||||
'contentUrl': `${siteDomain}${subjectImg}`,
|
||||
'width': 1080,
|
||||
'height': 1080,
|
||||
'caption': `${shortSido} ${gradeShort} ${subjectName} 과외`
|
||||
},
|
||||
{
|
||||
'@type': 'EducationalOrganization',
|
||||
'name': siteName,
|
||||
'url': siteDomain,
|
||||
'image': orgImages,
|
||||
'telephone': '+82-10-5961-5807',
|
||||
'description': pageDescription,
|
||||
'areaServed': {
|
||||
'@type': 'AdministrativeArea',
|
||||
'name': `${sido} ${sigungu} ${dong}`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Course',
|
||||
'name': `${dong} ${grade} ${subjectName} 1:1 맞춤 과외`,
|
||||
'description': `${dong} 인근 학교 내신 출제 경향 분석 및 ${subjectName} 1등급 도약 커리큘럼`,
|
||||
'provider': {
|
||||
'@type': 'Organization',
|
||||
'name': siteName
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'LocalBusiness',
|
||||
'name': `${regionTitle} 1:1 방문 과외`,
|
||||
'image': `${siteDomain}/img/og-preview.png`,
|
||||
'name': `${shortSido} ${gradeShort} 과외 · ${regionTitle} 1:1 방문 과외`,
|
||||
'image': orgImages,
|
||||
'url': canonicalUrl,
|
||||
'telephone': '+82-10-5961-5807',
|
||||
'priceRange': '₩₩',
|
||||
'address': {
|
||||
'@type': 'PostalAddress',
|
||||
'addressLocality': sido,
|
||||
'addressRegion': sigungu,
|
||||
'addressLocality': sigungu,
|
||||
'addressRegion': sido,
|
||||
'streetAddress': dong,
|
||||
'addressCountry': 'KR'
|
||||
},
|
||||
'areaServed': `${sido} ${sigungu} ${dong}`
|
||||
},
|
||||
{
|
||||
'@type': 'FAQPage',
|
||||
'mainEntity': [
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${dong} ${grade} ${subjectName} 방문 과외와 온라인 화상 과외 중 어떤 것이 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `학생과 학부모님의 선호에 따라 100% 자택 방문 대면 과외 또는 실시간 쌍방향 비대면 화상 과외 중 자유롭게 선택하실 수 있습니다. ${dong} 전 지역 방문 수업이 가능합니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${grade} ${subjectName} 전문 선생님이 학생과 잘 맞지 않으면 교체 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': '네, 1회 무료 모의수업을 통해 사전에 호흡을 맞추며, 정규 수업 시작 후에도 학생의 성향이나 요청에 따라 추가 비용 없이 100% 무료 교체 및 환불 규정을 보장합니다.'
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${grade} ${subjectName} 과외 수업 비용은 어떻게 되나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${grade} 내신 단계, 주당 수업 횟수, 수업 시간(1회 60분/90분/120분)에 따라 표준 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다. 무료 상담 시 상세 견적표를 안내해 드립니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${dong} 학교 중간·기말고사 직전 단기 ${subjectName} 족보 클리닉도 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, 시험 3~4주 전 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${grade} ${subjectName} 단기 속성 킬러 클리닉 프로그램도 상시 운영 중입니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${subjectName} 외에 다른 과목도 함께 상담받을 수 있나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${subjectName} 집중 신청은 물론, 국영수 또는 수탐 복합 패키지로 맞춤 구성하여 전 과목 플래너 관리와 함께 시간표를 편성하실 수 있습니다.`
|
||||
}
|
||||
}
|
||||
]
|
||||
'@type': 'Course',
|
||||
'name': isRegionOnly ? `${shortSido} 중등 수학 과외 · ${regionTitle} 초·중·고 1:1 맞춤 과외` : `${shortSido} ${gradeShort} ${subjectName} 과외 · ${dong} ${grade} ${subjectName} 1:1 맞춤 과외`,
|
||||
'description': `${shortSido} ${gradeShort} ${subjectName} 과외 및 ${dong} 인근 학교 내신 출제 경향 분석, ${subjectName} 1등급 도약 커리큘럼`,
|
||||
'url': canonicalUrl,
|
||||
'image': `${siteDomain}${subjectImg}`,
|
||||
'provider': {
|
||||
'@type': 'Organization',
|
||||
'name': siteName,
|
||||
'sameAs': siteDomain
|
||||
},
|
||||
'offers': {
|
||||
'@type': 'Offer',
|
||||
'category': 'Paid',
|
||||
'priceCurrency': 'KRW',
|
||||
'availability': 'https://schema.org/InStock',
|
||||
'url': canonicalUrl
|
||||
},
|
||||
'hasCourseInstance': {
|
||||
'@type': 'CourseInstance',
|
||||
'courseMode': ['onsite', 'online']
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'BreadcrumbList',
|
||||
'itemListElement': [
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 1,
|
||||
'name': '홈',
|
||||
'item': siteDomain
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 2,
|
||||
'name': sido,
|
||||
'item': `${siteDomain}/${encodeURIComponent(sido)}`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 3,
|
||||
'name': sigungu,
|
||||
'item': `${siteDomain}/${encodeURIComponent(sigungu)}`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 4,
|
||||
'name': `${dong} ${subjectName}`,
|
||||
'item': canonicalUrl
|
||||
}
|
||||
]
|
||||
'itemListElement': breadcrumbItems
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 블록 2: FAQPage 단독 JSON-LD
|
||||
const faqJsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'FAQPage',
|
||||
'mainEntity': [
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외(${dong}), 방문 수업과 화상 수업 모두 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, ${shortSido} ${gradeShort} ${subjectName} 과외 및 ${shortSido} ${gradeShort} 과외는 학생과 학부모님의 선호에 따라 100% 자택 방문 대면 수업 또는 실시간 쌍방향 화상 수업 중 자유롭게 선택하실 수 있으며, ${dong} ${gradeShort} ${subjectName} 과외 전 지역 방문 지도가 가능합니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} 과외 · ${dong} ${gradeShort} ${subjectName} 과외 전문 선생님이 학생과 맞지 않으면 교체 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, ${shortSido} ${gradeShort} ${subjectName} 과외 및 ${shortSido} ${gradeShort} 과외는 1회 무료 시범수업을 통해 사전에 호흡을 맞추며, ${dong} ${gradeShort} ${subjectName} 과외 정규 수업 시작 후에도 추가 비용 없이 100% 무료 선생님 교체 및 환불 규정을 보장합니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 및 ${dong} ${gradeShort} ${subjectName} 과외 수업 비용은 어떻게 되나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${shortSido} ${gradeShort} ${subjectName} 과외와 ${shortSido} ${gradeShort} 과외 비용은 ${grade} 내신 단계, 주당 수업 횟수, 수업 시간(1회 60분/90분/120분)에 따라 표준 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다. ${dong} ${gradeShort} ${subjectName} 과외 무료 상담 시 상세 견적표를 안내해 드립니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${dong} ${gradeShort} ${subjectName} 과외로 중간·기말고사 직전 단기 족보 클리닉도 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, ${shortSido} ${gradeShort} ${subjectName} 과외 및 ${shortSido} ${gradeShort} 과외 전담팀이 시험 3~4주 전 ${dong} 인근 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${dong} ${gradeShort} ${subjectName} 과외 단기 속성 클리닉도 상시 운영 중입니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 외에 국영수사과 다른 과목도 함께 상담받을 수 있나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${shortSido} ${gradeShort} ${subjectName} 과외 집중 신청은 물론, ${shortSido} ${gradeShort} 과외 국영수사과 복합 패키지 및 ${dong} ${gradeShort} ${subjectName} 과외 맞춤형 전 과목 플래너 관리로 시간표를 편성하실 수 있습니다.`
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 블록 3: ItemList 단독 JSON-LD (더세이브 검색결과 가로 이미지 줄 핵심 구조)
|
||||
const itemListJsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'ItemList',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 · ${dong} ${gradeShort} 과외`,
|
||||
'numberOfItems': carouselCourses.length,
|
||||
'itemListElement': carouselCourses.map((c, idx) => ({
|
||||
'@type': 'ListItem',
|
||||
'position': idx + 1,
|
||||
'name': c.name,
|
||||
'url': c.url,
|
||||
'image': c.image,
|
||||
'item': {
|
||||
'@type': 'Course',
|
||||
'name': c.name,
|
||||
'description': c.desc,
|
||||
'url': c.url,
|
||||
'image': c.image,
|
||||
'provider': {
|
||||
'@type': 'Organization',
|
||||
'name': siteName,
|
||||
'sameAs': siteDomain
|
||||
},
|
||||
'offers': {
|
||||
'@type': 'Offer',
|
||||
'category': 'Paid',
|
||||
'priceCurrency': 'KRW',
|
||||
'availability': 'https://schema.org/InStock',
|
||||
'url': c.url
|
||||
},
|
||||
'hasCourseInstance': {
|
||||
'@type': 'CourseInstance',
|
||||
'courseMode': ['onsite', 'online']
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
return {
|
||||
title: pageTitle,
|
||||
meta: [
|
||||
{ name: 'robots', content: 'index,follow' },
|
||||
{ name: 'naver-site-verification', content: 'dfb36e971115b72176e1c1e37c6ca27a95e855e3' },
|
||||
{ name: 'google-site-verification', content: 'DvXzTXFe_DBt8nrIiI7SwWYgOENNAWNW5op79syf5pM' },
|
||||
{ name: 'description', content: pageDescription },
|
||||
{ name: 'keywords', content: `${dong}과외, ${dong}${subjectName}과외, ${dong}${grade}과외, ${sigungu}과외, ${dong}학원, ${dong}내신대비, ${subjectName}1:1과외` },
|
||||
{ name: 'keywords', content: pageKeywords },
|
||||
{ property: 'og:type', content: 'website' },
|
||||
{ property: 'og:locale', content: 'ko_KR' },
|
||||
{ property: 'og:title', content: pageTitle },
|
||||
{ property: 'og:description', content: pageDescription },
|
||||
{ property: 'og:url', content: canonicalUrl },
|
||||
{ property: 'og:site_name', content: siteName },
|
||||
{ property: 'og:image', content: `${siteDomain}/img/og-preview.png` },
|
||||
{ property: 'og:image', content: `${siteDomain}${subjectImg}` },
|
||||
{ property: 'og:image:type', content: 'image/png' },
|
||||
{ property: 'og:image:width', content: '1200' },
|
||||
{ property: 'og:image:height', content: '630' },
|
||||
{ property: 'og:image:alt', content: `${shortSido} ${gradeShort} ${subjectName} 과외 · ${dong} ${gradeShort} ${subjectName} 과외` },
|
||||
{ name: 'twitter:card', content: 'summary_large_image' },
|
||||
{ name: 'twitter:title', content: pageTitle },
|
||||
{ name: 'twitter:description', content: pageDescription }
|
||||
{ name: 'twitter:description', content: pageDescription },
|
||||
{ name: 'twitter:image', content: `${siteDomain}${subjectImg}` }
|
||||
],
|
||||
link: [
|
||||
{ rel: 'canonical', href: canonicalUrl }
|
||||
@@ -153,7 +317,15 @@ export function generateSeoMeta(parsed: ParsedRouteParams, siteName = '티처브
|
||||
script: [
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(jsonLd)
|
||||
children: JSON.stringify(graphJsonLd)
|
||||
},
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(faqJsonLd)
|
||||
},
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(itemListJsonLd)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -8,46 +8,49 @@ const siteConfigs = {
|
||||
desc: '서울 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관',
|
||||
items: [
|
||||
{ title: '서울 초·중·고 1:1 맞춤 과외 매칭', link: 'https://aeseo.cloud/', desc: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 검증된 전문 선생님 100% 매칭' },
|
||||
{ title: '대치동 중학생 수학과외 1:1 맞춤 수업', link: 'https://aeseo.cloud/%EB%8C%80%EC%B9%98%EB%8F%99-%EC%A4%91%ED%95%99%EC%83%9D-%EC%88%98%ED%95%99', desc: '대치동 인근 학교별 기출 족보 분석 및 킬러문항 완파' },
|
||||
{ title: '대치동 고등학생 영어과외 1:1 맞춤 수업', link: 'https://aeseo.cloud/%EB%8C%80%EC%B9%98%EB%8F%99-%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D-%EC%98%81%EC%96%B4', desc: '내신 서술형 감점 0점화 및 수능 1등급 대비' },
|
||||
{ title: '목동 중학생 수학과외 1:1 맞춤 수업', link: 'https://aeseo.cloud/%EB%AA%A9%EB%8F%99-%EC%A4%91%ED%95%99%EC%83%9D-%EC%88%98%ED%95%99', desc: '목동 학군 맞춤 1:1 개념 정밀 코칭' }
|
||||
{ title: '대치동 중학생 수학과외 1:1 맞춤 수업', link: 'https://aeseo.cloud/%EB%8C%80%EC%B9%98%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99', desc: '대치동 인근 학교별 기출 족보 분석 및 킬러문항 완파' },
|
||||
{ title: '대치동 고등학생 영어과외 1:1 맞춤 수업', link: 'https://aeseo.cloud/%EB%8C%80%EC%B9%98%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4', desc: '내신 서술형 감점 0점화 및 수능 1등급 대비' },
|
||||
{ title: '목동 중학생 수학과외 1:1 맞춤 수업', link: 'https://aeseo.cloud/%EB%AA%A9%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99', desc: '목동 학군 맞춤 1:1 개념 정밀 코칭' }
|
||||
]
|
||||
},
|
||||
gyeonggi: {
|
||||
siteName: '로열클래스 1:1 과외',
|
||||
siteName: '새솔 1:1 맞춤과외',
|
||||
siteDomain: 'https://aeseo.shop',
|
||||
desc: '경기 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관',
|
||||
items: [
|
||||
{ title: '경기 초·중·고 1:1 맞춤 과외 매칭', link: 'https://aeseo.shop/', desc: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지' },
|
||||
{ title: '분당동 중학생 수학과외 1:1 맞춤 수업', link: 'https://aeseo.shop/%EB%B6%84%EB%8B%B9%EB%8F%99-%EC%A4%91%ED%95%99%EC%83%9D-%EC%88%98%ED%95%99', desc: '분당 인근 학교별 내신 기출 분석' },
|
||||
{ title: '일산동 고등학생 영어과외 1:1 맞춤 수업', link: 'https://aeseo.shop/%EC%9D%BC%EC%82%B0%EB%8F%99-%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D-%EC%98%81%EC%96%B4', desc: '일산 학군 내신 서술형 대비' }
|
||||
{ title: '수내동 중학생 수학과외 1:1 맞춤 수업', link: 'https://aeseo.shop/%EC%88%98%EB%82%B4%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99', desc: '분당 수내동 인근 학교별 내신 기출 분석' },
|
||||
{ title: '마두동 고등학생 영어과외 1:1 맞춤 수업', link: 'https://aeseo.shop/%EB%A7%88%EB%91%90%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4', desc: '일산 학군 내신 서술형 대비' }
|
||||
]
|
||||
},
|
||||
incheon: {
|
||||
siteName: '로열클래스 1:1 과외',
|
||||
siteName: '튜터온',
|
||||
siteDomain: 'https://aeseo.site',
|
||||
desc: '인천 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관',
|
||||
items: [
|
||||
{ title: '인천 초·중·고 1:1 맞춤 과외 매칭', link: 'https://aeseo.site/', desc: '송도·청라 등 인천 전지역 과외 비용 비교 및 시범수업 신청' },
|
||||
{ title: '송도동 중학생 수학과외 1:1 맞춤 수업', link: 'https://aeseo.site/%EC%86%A1%EB%8F%84%EB%8F%99-%EC%A4%91%ED%95%99%EC%83%9D-%EC%88%98%ED%95%99', desc: '송도 학군 1:1 개념 정밀 클리닉' }
|
||||
{ title: '송도동 중학생 수학과외 1:1 맞춤 수업', link: 'https://aeseo.site/%EC%86%A1%EB%8F%84%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99', desc: '송도 학군 1:1 개념 정밀 클리닉' },
|
||||
{ title: '청라동 고등학생 영어과외 1:1 맞춤 수업', link: 'https://aeseo.site/%EC%B2%AD%EB%9D%BC%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4', desc: '청라 학군 내신 서술형 1:1 대비' }
|
||||
]
|
||||
},
|
||||
daegu: {
|
||||
siteName: '과외매칭센터',
|
||||
siteName: '티처브릿지',
|
||||
siteDomain: 'https://soohyun.store',
|
||||
desc: '대구 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관',
|
||||
items: [
|
||||
{ title: '대구 초·중·고 1:1 맞춤 과외 매칭', link: 'https://soohyun.store/', desc: '수성구 등 대구 전지역 과외 비용 비교 및 시범수업 신청' },
|
||||
{ title: '범어동 중학생 수학과외 1:1 맞춤 수업', link: 'https://soohyun.store/%EB%B2%94%EC%96%B4%EB%8F%99-%EC%A4%91%ED%95%99%EC%83%9D-%EC%88%98%ED%95%99', desc: '수성구 학군 기출 족보 완파' }
|
||||
{ title: '범어동 중학생 수학과외 1:1 맞춤 수업', link: 'https://soohyun.store/%EB%B2%94%EC%96%B4%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99', desc: '수성구 학군 기출 족보 완파' },
|
||||
{ title: '황금동 고등학생 영어과외 1:1 맞춤 수업', link: 'https://soohyun.store/%ED%99%A9%EA%B8%88%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4', desc: '수성구 황금동 내신 1등급 집중 코칭' }
|
||||
]
|
||||
},
|
||||
busan: {
|
||||
siteName: '가온에듀',
|
||||
siteName: '공부짝꿍',
|
||||
siteDomain: 'https://soohyun.cloud',
|
||||
desc: '부산 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관',
|
||||
items: [
|
||||
{ title: '부산 초·중·고 1:1 맞춤 과외 매칭', link: 'https://soohyun.cloud/', desc: '해운대·수영·동래 등 부산 전지역 과외 비용 비교 및 시범수업 신청' },
|
||||
{ title: '우동 중학생 수학과외 1:1 맞춤 수업', link: 'https://soohyun.cloud/%EC%9A%B0%EB%8F%99-%EC%A4%91%ED%95%99%EC%83%9D-%EC%88%98%ED%95%99', desc: '해운대구 관내 학교 기출 분석' }
|
||||
{ title: '우동 중학생 수학과외 1:1 맞춤 수업', link: 'https://soohyun.cloud/%EC%9A%B0%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99', desc: '해운대구 관내 학교 기출 분석' },
|
||||
{ title: '사직동 고등학생 영어과외 1:1 맞춤 수업', link: 'https://soohyun.cloud/%EC%82%AC%EC%A7%81%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4', desc: '동래구 사직동 내신 서술형 집중 대비' }
|
||||
]
|
||||
},
|
||||
gwangju: {
|
||||
@@ -56,7 +59,8 @@ const siteConfigs = {
|
||||
desc: '광주 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관',
|
||||
items: [
|
||||
{ title: '광주 초·중·고 1:1 맞춤 과외 매칭', link: 'https://aeseo.store/', desc: '봉선·수완 등 광주 전지역 과외 비용 비교 및 시범수업 신청' },
|
||||
{ title: '봉선동 중학생 수학과외 1:1 맞춤 수업', link: 'https://aeseo.store/%EB%B4%89%EC%84%A0%EB%8F%99-%EC%A4%91%ED%95%99%EC%83%9D-%EC%88%98%ED%95%99', desc: '봉선동 학군 내신 1등급 솔루션' }
|
||||
{ title: '봉선동 중학생 수학과외 1:1 맞춤 수업', link: 'https://aeseo.store/%EB%B4%89%EC%84%A0%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99', desc: '봉선동 학군 내신 1등급 솔루션' },
|
||||
{ title: '수완동 고등학생 영어과외 1:1 맞춤 수업', link: 'https://aeseo.store/%EC%88%98%EC%99%84%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4', desc: '광산구 수완동 내신 서술형 완벽 대비' }
|
||||
]
|
||||
},
|
||||
ulsan: {
|
||||
@@ -65,7 +69,8 @@ const siteConfigs = {
|
||||
desc: '울산 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관',
|
||||
items: [
|
||||
{ title: '울산 초·중·고 1:1 맞춤 과외 매칭', link: 'https://soohyun.xyz/', desc: '옥동·신정 등 울산 전지역 과외 비용 비교 및 시범수업 신청' },
|
||||
{ title: '옥동 중학생 수학과외 1:1 맞춤 수업', link: 'https://soohyun.xyz/%EC%98%A5%EB%8F%99-%EC%A4%91%ED%95%99%EC%83%9D-%EC%88%98%ED%95%99', desc: '옥동 학원가 대비 1:1 밀착 코칭' }
|
||||
{ title: '옥동 중학생 수학과외 1:1 맞춤 수업', link: 'https://soohyun.xyz/%EC%98%A5%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99', desc: '옥동 학원가 대비 1:1 밀착 코칭' },
|
||||
{ title: '신정동 고등학생 영어과외 1:1 맞춤 수업', link: 'https://soohyun.xyz/%EC%8B%A0%EC%A0%95%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4', desc: '남구 신정동 내신 서술형 집중 관리' }
|
||||
]
|
||||
},
|
||||
site1: {
|
||||
@@ -73,7 +78,10 @@ const siteConfigs = {
|
||||
siteDomain: 'https://aeseo.cloud',
|
||||
desc: '서울 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관',
|
||||
items: [
|
||||
{ title: '서울 초·중·고 1:1 맞춤 과외 매칭', link: 'https://aeseo.cloud/', desc: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지' }
|
||||
{ title: '서울 초·중·고 1:1 맞춤 과외 매칭', link: 'https://aeseo.cloud/', desc: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지' },
|
||||
{ title: '대치동 중학생 수학과외 1:1 맞춤 수업', link: 'https://aeseo.cloud/%EB%8C%80%EC%B9%98%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99', desc: '대치동 인근 학교별 기출 족보 분석 및 킬러문항 완파' },
|
||||
{ title: '대치동 고등학생 영어과외 1:1 맞춤 수업', link: 'https://aeseo.cloud/%EB%8C%80%EC%B9%98%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4', desc: '내신 서술형 감점 0점화 및 수능 1등급 대비' },
|
||||
{ title: '목동 중학생 수학과외 1:1 맞춤 수업', link: 'https://aeseo.cloud/%EB%AA%A9%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99', desc: '목동 학군 맞춤 1:1 개념 정밀 코칭' }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,38 +2,33 @@
|
||||
<section class="faq-section">
|
||||
<div class="section-header">
|
||||
<span class="section-badge">궁금한 점을 풀어드립니다</span>
|
||||
<h2 class="section-title">{{ regionDong }} 1:1 과외 자주 묻는 질문</h2>
|
||||
<h2 class="section-title">{{ shortSido }} {{ gradeShort }} {{ subjectName }} 과외 · {{ regionDong }} 1:1 과외 자주 묻는 질문</h2>
|
||||
<p class="section-desc">학부모님들께서 가장 많이 문의하시는 내용을 모았습니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="faq-list">
|
||||
<div
|
||||
<details
|
||||
v-for="(faq, idx) in faqs"
|
||||
:key="idx"
|
||||
class="faq-item"
|
||||
:class="{ active: openIndex === idx }"
|
||||
class="faq-item qa"
|
||||
:open="idx === 0"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="faq-question"
|
||||
@click="toggle(idx)"
|
||||
:aria-expanded="openIndex === idx"
|
||||
>
|
||||
<summary class="faq-question">
|
||||
<span class="q-icon">Q</span>
|
||||
<span class="q-text">{{ faq.q }}</span>
|
||||
<span class="toggle-icon">{{ openIndex === idx ? '▲' : '▼' }}</span>
|
||||
</button>
|
||||
<div v-show="openIndex === idx" class="faq-answer">
|
||||
<span class="toggle-icon">▼</span>
|
||||
</summary>
|
||||
<div class="faq-answer ans">
|
||||
<span class="a-icon">A</span>
|
||||
<p class="a-text">{{ faq.a }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
regionDong: {
|
||||
@@ -44,38 +39,40 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: '중등'
|
||||
},
|
||||
shortSido: {
|
||||
type: String,
|
||||
default: '광주'
|
||||
},
|
||||
subjectName: {
|
||||
type: String,
|
||||
default: '영어'
|
||||
default: '수학'
|
||||
}
|
||||
})
|
||||
|
||||
const openIndex = ref(0)
|
||||
|
||||
const toggle = (idx) => {
|
||||
openIndex.value = openIndex.value === idx ? -1 : idx
|
||||
}
|
||||
|
||||
const faqs = computed(() => [
|
||||
{
|
||||
q: `${props.regionDong} ${props.grade} ${props.subjectName} 방문 과외와 온라인 화상 과외 중 어떤 것이 가능한가요?`,
|
||||
a: `학생과 학부모님의 선호에 따라 100% 자택 방문 대면 과외 또는 실시간 쌍방향 비대면 화상 과외 중 자유롭게 선택하실 수 있습니다. ${props.regionDong} 전 지역 방문 수업이 가능합니다.`
|
||||
q: `${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외 및 ${props.regionDong} ${props.grade} ${props.subjectName} 방문 과외와 화상 과외 중 어떤 것이 가능한가요?`,
|
||||
a: `학생과 학부모님의 선호에 따라 ${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외 100% 자택 방문 대면 수업 또는 실시간 쌍방향 화상 과외 중 자유롭게 선택하실 수 있습니다. ${props.regionDong} 전 지역 방문 수업이 가능합니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.grade} ${props.subjectName} 전문 선생님이 학생과 잘 맞지 않으면 교체 가능한가요?`,
|
||||
a: '네, 1회 무료 모의수업을 통해 사전에 호흡을 맞추며, 정규 수업 시작 후에도 학생의 성향이나 요청에 따라 추가 비용 없이 100% 무료 교체 및 환불 규정을 보장합니다.'
|
||||
q: `${props.shortSido} ${props.gradeShort} 과외 · ${props.regionDong} ${props.grade} ${props.subjectName} 전문 선생님이 학생과 맞지 않으면 교체 가능한가요?`,
|
||||
a: `네, ${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외는 1회 무료 모의수업을 통해 사전에 호흡을 맞추며, 정규 수업 시작 후에도 학생의 성향이나 요청에 따라 추가 비용 없이 100% 무료 교체 및 환불 규정을 보장합니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.grade} ${props.subjectName} 과외 수업 비용은 어떻게 되나요?`,
|
||||
a: `${props.grade} 내신 단계, 주당 수업 횟수, 수업 시간(1회 60분/90분/120분)에 따라 표준 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다. 무료 상담 시 상세 견적표를 안내해 드립니다.`
|
||||
q: `${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외 및 ${props.regionDong} ${props.grade} ${props.subjectName} 과외 수업 비용은 어떻게 되나요?`,
|
||||
a: `${props.shortSido} ${props.gradeShort} 과외는 ${props.grade} 내신 단계, 주당 수업 횟수, 수업 시간(1회 60분/90분/120분)에 따라 표준 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다. 무료 상담 시 상세 견적표를 안내해 드립니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.regionDong} 학교 중간·기말고사 직전 단기 ${props.subjectName} 족보 클리닉도 가능한가요?`,
|
||||
a: `네, 시험 3~4주 전 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${props.grade} ${props.subjectName} 단기 속성 킬러 클리닉 프로그램도 상시 운영 중입니다.`
|
||||
q: `${props.regionDong} 학교 중간·기말고사 직전 단기 ${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외 족보 클리닉도 가능한가요?`,
|
||||
a: `네, 시험 3~4주 전 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${props.regionDong} ${props.grade} ${props.subjectName} 과외 단기 속성 킬러 클리닉 프로그램도 상시 운영 중입니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.subjectName} 외에 다른 과목도 함께 상담받을 수 있나요?`,
|
||||
a: `${props.subjectName} 집중 신청은 물론, 국영수 또는 수탐 복합 패키지로 맞춤 구성하여 전 과목 플래너 관리와 함께 시간표를 편성하실 수 있습니다.`
|
||||
q: `${props.shortSido} ${props.gradeShort} ${props.subjectName} 과외 외에 다른 과목도 함께 상담받을 수 있나요?`,
|
||||
a: `${props.subjectName} 집중 신청은 물론, 국영수 또는 수탐 복합 ${props.shortSido} ${props.gradeShort} 과외 패키지로 맞춤 구성하여 전 과목 플래너 관리와 함께 시간표를 편성하실 수 있습니다.`
|
||||
}
|
||||
])
|
||||
</script>
|
||||
@@ -146,6 +143,11 @@ const faqs = computed(() => [
|
||||
font-size: clamp(0.9rem, 2.2vw, 1.02rem);
|
||||
font-weight: 800;
|
||||
color: var(--text-color, #0f172a);
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.faq-question::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.q-icon {
|
||||
@@ -172,6 +174,11 @@ const faqs = computed(() => [
|
||||
font-size: 0.8rem;
|
||||
color: #94a3b8;
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
details[open] .toggle-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.faq-answer {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="focus-header">
|
||||
<span class="focus-badge">{{ isElementary ? '초등 맞춤 집중 케어' : `${displayGrade} 실전 시험 케어` }}</span>
|
||||
<h2 class="focus-main-title">
|
||||
{{ regionDong }} {{ displayGrade }} {{ displaySubject }}과외
|
||||
{{ shortSido ? `${shortSido} ` : '' }}{{ regionDong }} {{ displayGrade }} {{ displaySubject }}과외
|
||||
<span class="text-accent">5대 핵심 솔루션</span>
|
||||
</h2>
|
||||
<p class="focus-sub-desc">
|
||||
@@ -12,7 +12,7 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 네이버 5개 멀티 썸네일 스니펫 및 상담 링크 매칭용 5개 리스트 -->
|
||||
<!-- 네이버 5개 멀티 썸네일 스니펫 및 상담 링크 매칭용 가로 5열 캐러셀 -->
|
||||
<div class="focus-grid">
|
||||
<a
|
||||
v-for="(item, idx) in programList"
|
||||
@@ -21,27 +21,30 @@
|
||||
class="focus-card"
|
||||
:title="`${item.title} 상담 신청`"
|
||||
>
|
||||
<div class="focus-thumb-wrap">
|
||||
<img
|
||||
:src="item.image"
|
||||
:alt="`${item.title} 1:1 맞춤 지도`"
|
||||
width="500"
|
||||
height="500"
|
||||
loading="lazy"
|
||||
class="focus-img"
|
||||
/>
|
||||
<span class="step-tag">STEP 0{{ idx + 1 }}</span>
|
||||
</div>
|
||||
|
||||
<div class="focus-info">
|
||||
<div class="focus-item-tag">{{ item.tag }}</div>
|
||||
<strong class="focus-item-title">{{ item.title }}</strong>
|
||||
<p class="focus-item-desc">{{ item.desc }}</p>
|
||||
<div class="focus-cta-link">
|
||||
<span>1:1 상담 예약</span>
|
||||
<span class="arrow-sym">→</span>
|
||||
<figure class="focus-figure m-0 flex flex-col flex-1">
|
||||
<div class="focus-thumb-wrap">
|
||||
<img
|
||||
:src="item.image"
|
||||
:alt="item.title"
|
||||
width="1080"
|
||||
height="1080"
|
||||
decoding="async"
|
||||
loading="eager"
|
||||
fetchpriority="high"
|
||||
class="focus-img"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<figcaption class="focus-info">
|
||||
<div class="focus-item-tag">{{ item.tag }}</div>
|
||||
<h3 class="focus-item-title m-0">{{ item.title }}</h3>
|
||||
<p class="focus-item-desc">{{ item.desc }}</p>
|
||||
<div class="focus-cta-link">
|
||||
<span>1:1 상담 예약</span>
|
||||
<span class="arrow-sym">→</span>
|
||||
</div>
|
||||
</figcaption>
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -56,6 +59,14 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: '중등'
|
||||
},
|
||||
shortSido: {
|
||||
type: String,
|
||||
default: '광주'
|
||||
},
|
||||
subjectName: {
|
||||
type: String,
|
||||
default: '수학'
|
||||
@@ -78,7 +89,7 @@ const displaySubject = computed(() => {
|
||||
return props.subjectName || '수학'
|
||||
})
|
||||
|
||||
// 초등 vs 중등/고등 5개 항목 분기
|
||||
// 초등 vs 중등/고등 5개 항목 분기 (네이버 썸네일 추출 가능한 고해상도 실사 .png 5종 적용)
|
||||
const programList = computed(() => {
|
||||
const dong = props.regionDong ? `${props.regionDong} ` : ''
|
||||
const sub = displaySubject.value
|
||||
@@ -90,31 +101,31 @@ const programList = computed(() => {
|
||||
tag: '개념 완성',
|
||||
title: `${dong}초등 ${sub}과외 - 기초학습`,
|
||||
desc: '개념 쏙쏙 이해와 튼튼한 연산 기본기 완성',
|
||||
image: '/images/focus/elem-1-basic.svg'
|
||||
image: '/img/math-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '학습 코칭',
|
||||
title: `${dong}초등 ${sub}과외 - 공부방법`,
|
||||
desc: '스스로 원리를 깨우치는 올바른 문제 해결력',
|
||||
image: '/images/focus/elem-2-method.svg'
|
||||
image: '/img/english-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '밀착 피드백',
|
||||
title: `${dong}초등 ${sub}과외 - 숙제검사`,
|
||||
desc: '매일 1:1 오답 점검과 꼼꼼한 피드백 클리닉',
|
||||
image: '/images/focus/elem-3-homework.svg'
|
||||
image: '/img/korean-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '자기주도',
|
||||
title: `${dong}초등 ${sub}과외 - 공부습관`,
|
||||
desc: '매일 스스로 책상에 앉는 주도적 학습 루틴',
|
||||
image: '/images/focus/elem-4-habit.svg'
|
||||
image: '/img/science-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '상위권 도약',
|
||||
title: `${dong}초등 ${sub}과외 - 중등대비`,
|
||||
desc: '중학교 내신 서술형과 심화 개념 선행 마스터',
|
||||
image: '/images/focus/elem-5-middleprep.svg'
|
||||
image: '/img/social-studies-tutoring.png'
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -125,31 +136,31 @@ const programList = computed(() => {
|
||||
tag: '기출 정복',
|
||||
title: `${dong}${grd} 중간고사 ${sub}과외`,
|
||||
desc: '학교별 기출 족보 완벽 분석 및 서술형 킬러 대비',
|
||||
image: '/images/focus/sec-1-midterm.svg'
|
||||
image: '/img/math-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '학기말 총력',
|
||||
title: `${dong}${grd} 기말고사 ${sub}과외`,
|
||||
desc: '전 범위 오답 분석 및 취약 유형 완벽 클리닉',
|
||||
image: '/images/focus/sec-2-final.svg'
|
||||
image: '/img/english-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '수능·전국연합',
|
||||
title: `${dong}${grd} 모의고사 ${sub}과외`,
|
||||
desc: '수능형 사고력 확장 및 실전 시간 배분 특훈',
|
||||
image: '/images/focus/sec-3-mock.svg'
|
||||
image: '/img/korean-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '내신 만점',
|
||||
title: `${dong}${grd} 수행평가 ${sub}과외`,
|
||||
desc: '조건 감점 0점화 및 과제·보고서 완벽 케어',
|
||||
image: '/images/focus/sec-4-assessment.svg'
|
||||
image: '/img/science-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '1등급 집중',
|
||||
title: `${dong}${grd} 내신대비 ${sub}과외`,
|
||||
desc: '관내 교과서·부교재 적중 1:1 맞춤 지도',
|
||||
image: '/images/focus/sec-5-schoolprep.svg'
|
||||
image: '/img/social-studies-tutoring.png'
|
||||
}
|
||||
]
|
||||
})
|
||||
@@ -202,10 +213,10 @@ const programList = computed(() => {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 5열 카드 그리드 */
|
||||
/* 가로 1열 5칸 캐러셀 그리드 */
|
||||
.focus-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
grid-template-columns: repeat(5, minmax(180px, 1fr));
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
@@ -234,6 +245,7 @@ const programList = computed(() => {
|
||||
aspect-ratio: 1 / 1;
|
||||
background: #f1f5f9;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.focus-img {
|
||||
@@ -248,20 +260,6 @@ const programList = computed(() => {
|
||||
transform: scale(1.04);
|
||||
}
|
||||
|
||||
.step-tag {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
padding: 2px 8px;
|
||||
background: rgba(0, 0, 0, 0.55);
|
||||
backdrop-filter: blur(4px);
|
||||
color: #ffffff;
|
||||
font-size: 0.68rem;
|
||||
font-weight: 800;
|
||||
border-radius: 4px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.focus-info {
|
||||
padding: 14px 12px;
|
||||
display: flex;
|
||||
@@ -281,7 +279,7 @@ const programList = computed(() => {
|
||||
font-weight: 800;
|
||||
color: #0f172a;
|
||||
line-height: 1.35;
|
||||
margin-bottom: 6px;
|
||||
margin: 0 0 6px 0;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
@@ -313,52 +311,37 @@ const programList = computed(() => {
|
||||
transform: translateX(3px);
|
||||
}
|
||||
|
||||
/* 태블릿 및 모바일 반응형 */
|
||||
@media (max-width: 960px) {
|
||||
/* 태블릿 및 모바일 가로 스크롤 캐러셀 반응형 */
|
||||
@media (max-width: 1024px) {
|
||||
.focus-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.focus-grid {
|
||||
grid-template-columns: 1fr;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x mandatory;
|
||||
gap: 12px;
|
||||
padding-bottom: 12px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.focus-card {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex: 0 0 210px;
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.focus-grid {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x mandatory;
|
||||
gap: 12px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.focus-thumb-wrap {
|
||||
width: 105px;
|
||||
height: 105px;
|
||||
aspect-ratio: 1 / 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.focus-info {
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.focus-item-title {
|
||||
font-size: 0.88rem;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.focus-item-desc {
|
||||
font-size: 0.74rem;
|
||||
margin-bottom: 6px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.focus-cta-link {
|
||||
padding-top: 4px;
|
||||
font-size: 0.72rem;
|
||||
.focus-card {
|
||||
flex: 0 0 200px;
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,27 +1,45 @@
|
||||
<template>
|
||||
<header class="hero-banner-clean bg-white border-b border-slate-200/80 pt-10 sm:pt-14 pb-14 sm:pb-18 px-4 sm:px-6 relative overflow-hidden text-center">
|
||||
|
||||
<section
|
||||
class="hero-banner hero-banner-clean bg-white border-b border-slate-200/80 pt-10 sm:pt-14 pb-14 sm:pb-18 px-4 sm:px-6 relative overflow-hidden text-center"
|
||||
itemscope itemtype="https://schema.org/Course">
|
||||
|
||||
<!-- 은은한 상단 엠비언트 라이트 -->
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-blue-50/40 via-transparent to-transparent pointer-events-none"></div>
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-blue-50/40 via-transparent to-transparent pointer-events-none">
|
||||
</div>
|
||||
|
||||
<div class="max-w-4xl mx-auto relative z-10">
|
||||
|
||||
|
||||
<!-- 신뢰 보증 뱃지 -->
|
||||
<div class="inline-flex items-center gap-2 px-3.5 py-1.5 rounded-full text-xs font-semibold bg-slate-50 border border-slate-200 text-slate-700 shadow-xs mb-5">
|
||||
<div
|
||||
class="inline-flex items-center gap-2 px-3.5 py-1.5 rounded-full text-xs font-semibold bg-slate-50 border border-slate-200 text-slate-700 shadow-xs mb-5">
|
||||
<span class="w-2 h-2 rounded-full bg-blue-600"></span>
|
||||
<span>{{ region.dong }} 학군 전담 | 서울대·연고대 및 베테랑 강사진 100% 신원 보증</span>
|
||||
</div>
|
||||
|
||||
<!-- SEO 메인 H1 (사용자 지정 롱테일 조합형: [지역] + [학년] + [과목]과외 + 검증된 전문 선생님 100% 매칭) -->
|
||||
<h1 class="text-2xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.22] sm:leading-[1.18] mb-4">
|
||||
<span>{{ displayRegionName }} {{ grade }} {{ subjectName }}과외</span><br />
|
||||
<span class="text-blue-600">우리 아이 맞춤 검증된 전문 선생님 100% 매칭</span>
|
||||
</h1>
|
||||
|
||||
<!-- 서브 카피 (비용 시세 비교 + 학교 기출 분석 + 무료 시범수업 신뢰 트리거) -->
|
||||
<p class="text-xs sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-7">
|
||||
{{ region.dong }} 인근 학교별 기출 분석부터 과외 비용·시세 비교, 취약 개념 클리닉까지.<br class="hidden sm:inline" />
|
||||
직접 수업받아보고 결정하는 <strong>1:1 무료 방문·화상 시범수업</strong>을 신청하세요.
|
||||
<!-- 1. H1 -->
|
||||
<h1 itemprop="headline"
|
||||
class="text-2xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.22] sm:leading-[1.18] mb-3">
|
||||
<span class="highlight text-blue-600">{{ shortSidoName }} {{ gradeShortName }} {{ subjectName }} 과외 · {{
|
||||
region.dong }} {{ grade }} {{ subjectName }}과외</span><br />
|
||||
1:1 맞춤 학습으로 성적 역전!
|
||||
</h1>
|
||||
<!-- 2. meta (H1 바로 다음 줄) -->
|
||||
<meta itemprop="name"
|
||||
:content="`${shortSidoName} ${gradeShortName} ${subjectName} 과외 · ${shortSidoName} ${gradeShortName} 과외 (${region.dong})`" />
|
||||
<meta itemprop="description"
|
||||
:content="`${shortSidoName} ${gradeShortName} ${subjectName} 과외 및 ${shortSidoName} ${gradeShortName} 과외 전문 매칭. ${displayRegionName} ${grade} ${subjectName} 1:1 방문·화상 맞춤 수업`" />
|
||||
<meta itemprop="keywords"
|
||||
:content="`${shortSidoName} ${gradeShortName} ${subjectName} 과외, ${shortSidoName} ${gradeShortName} 과외, ${region.dong} ${gradeShortName} ${subjectName} 과외, ${region.dong} ${gradeShortName} 과외, ${displayRegionName} ${grade} ${subjectName}과외`" />
|
||||
<meta itemprop="image" content="/img/math-tutoring.png" />
|
||||
<!-- 3. H2 (meta 바로 다음 줄) -->
|
||||
<h2 class="hero-subtitle">
|
||||
{{ shortSidoName }} {{ gradeShortName }} 과외 · {{ displayRegionName }} {{ gradeShortName }} {{ subjectName }} 과외
|
||||
검증된 전문 선생님 1:1 매칭
|
||||
</h2>
|
||||
<!-- 4. 일반글 p (H2 바로 다음 줄) -->
|
||||
<p class="sub-headline text-xs sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-7">
|
||||
{{ shortSidoName }} {{ gradeShortName }} {{ subjectName }} 과외 및 {{ shortSidoName }} {{ gradeShortName }} 과외를
|
||||
찾으시는 학부모님을 위해 {{ region.dong }} 인근 학교별 기출 족보 분석부터 개인별 취약 개념 완벽 보완, 투명한 과외비 안내와 무료 시범수업까지 1:1 밀착 커리큘럼을 제공합니다.
|
||||
</p>
|
||||
|
||||
<!-- 4대 핵심 신뢰 지표 바 -->
|
||||
@@ -61,10 +79,8 @@
|
||||
|
||||
<!-- CTA 그룹 -->
|
||||
<div class="flex flex-col items-center gap-3.5 mb-6">
|
||||
<a
|
||||
href="#consult-section"
|
||||
class="inline-flex items-center justify-center gap-2 w-full max-w-md py-4 px-6 bg-blue-600 hover:bg-blue-700 text-white font-extrabold text-sm sm:text-base rounded-xl shadow-md hover:shadow-lg transition-all"
|
||||
>
|
||||
<a href="#consult-section"
|
||||
class="inline-flex items-center justify-center gap-2 w-full max-w-md py-4 px-6 bg-blue-600 hover:bg-blue-700 text-white font-extrabold text-sm sm:text-base rounded-xl shadow-md hover:shadow-lg transition-all">
|
||||
<i class="fa-solid fa-file-signature text-base"></i>
|
||||
<span>{{ region.dong }} 과외 시세 확인 & 무료 시범수업 신청</span>
|
||||
</a>
|
||||
@@ -75,7 +91,8 @@
|
||||
</div>
|
||||
|
||||
<!-- 실시간 접수 롤링 바 -->
|
||||
<div class="inline-flex items-center gap-2.5 bg-slate-100/90 border border-slate-200/80 rounded-full px-4 py-1.5 text-xs text-slate-600 shadow-xs mb-6">
|
||||
<div
|
||||
class="inline-flex items-center gap-2.5 bg-slate-100/90 border border-slate-200/80 rounded-full px-4 py-1.5 text-xs text-slate-600 shadow-xs mb-6">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse"></span>
|
||||
<span class="font-bold text-slate-700">실시간 매칭</span>
|
||||
<span class="text-slate-300">|</span>
|
||||
@@ -84,15 +101,24 @@
|
||||
|
||||
<!-- 태그 목록 -->
|
||||
<div class="flex justify-center flex-wrap gap-1.5">
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ region.dong }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ region.dong }}{{ subjectName }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ grade }}내신대비</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#과외비용시세</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#1대1무료시범수업</span>
|
||||
<span
|
||||
class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{
|
||||
shortSidoName }}{{ gradeShortName }}{{ subjectName }}과외</span>
|
||||
<span
|
||||
class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{
|
||||
shortSidoName }}{{ gradeShortName }}과외</span>
|
||||
<span
|
||||
class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{
|
||||
region.dong }}과외</span>
|
||||
<span
|
||||
class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{
|
||||
region.dong }}{{ subjectName }}과외</span>
|
||||
<span
|
||||
class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#1대1무료시범수업</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</header>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -111,12 +137,24 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
subjectName: {
|
||||
type: String,
|
||||
default: '수학'
|
||||
}
|
||||
})
|
||||
|
||||
const shortSidoName = computed(() => {
|
||||
return (props.region?.sido || '').replace(/특별시|광역시|특별자치시|도/g, '').trim()
|
||||
})
|
||||
|
||||
const gradeShortName = computed(() => {
|
||||
return props.gradeShort || (props.grade === '초등학생' ? '초등' : props.grade === '고등학생' ? '고등' : '중등')
|
||||
})
|
||||
|
||||
const noticeIdx = ref(0)
|
||||
let timer = null
|
||||
|
||||
@@ -171,4 +209,12 @@ const displayRegionName = computed(() => {
|
||||
.hero-banner-clean {
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-size: 1.15rem;
|
||||
font-weight: 700;
|
||||
color: #334155;
|
||||
margin-bottom: 0.75rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -116,15 +116,15 @@ const nearbyDongs = computed(() => {
|
||||
}
|
||||
|
||||
// 만약 동일 구의 동이 부족하면 전체에서 다른 동 가져오기
|
||||
if (candidates.length < 5) {
|
||||
if (candidates.length < 12) {
|
||||
const others = allList
|
||||
.filter(r => r.dong !== curDong && !candidates.includes(r.dong))
|
||||
.map(r => r.dong)
|
||||
candidates = [...candidates, ...others]
|
||||
}
|
||||
|
||||
// 중복 제거 후 6개 반환
|
||||
return Array.from(new Set(candidates)).slice(0, 6)
|
||||
// 중복 제거 후 12개 반환
|
||||
return Array.from(new Set(candidates)).slice(0, 12)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -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://aeseo.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>
|
||||
|
||||
@@ -25,20 +25,20 @@
|
||||
"dong": "삼도동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 광산구 서봉동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 광산구 서봉동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "광산구",
|
||||
"dong": "서봉동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 광산구 소촌동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 광산구 소촌동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "광산구",
|
||||
"dong": "소촌동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 광산구 송정동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 광산구 송정동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "광산구",
|
||||
"dong": "송정동"
|
||||
},
|
||||
@@ -73,14 +73,14 @@
|
||||
"dong": "운남동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 광산구 운수동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 광산구 운수동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "광산구",
|
||||
"dong": "운수동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 광산구 월계동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 광산구 월계동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "광산구",
|
||||
"dong": "월계동"
|
||||
},
|
||||
@@ -91,8 +91,8 @@
|
||||
"dong": "임곡동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 광산구 장덕동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 광산구 장덕동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "광산구",
|
||||
"dong": "장덕동"
|
||||
},
|
||||
@@ -103,26 +103,26 @@
|
||||
"dong": "하남동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 남구 방림동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 남구 방림동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "남구",
|
||||
"dong": "방림동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 남구 백운동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 남구 백운동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "남구",
|
||||
"dong": "백운동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 남구 봉선동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 남구 봉선동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "남구",
|
||||
"dong": "봉선동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 남구 송하동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 남구 송하동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "남구",
|
||||
"dong": "송하동"
|
||||
},
|
||||
@@ -139,8 +139,8 @@
|
||||
"dong": "월산동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 남구 주월동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 남구 주월동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "남구",
|
||||
"dong": "주월동"
|
||||
},
|
||||
@@ -151,8 +151,8 @@
|
||||
"dong": "진월동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 동구 계림동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 동구 계림동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "동구",
|
||||
"dong": "계림동"
|
||||
},
|
||||
@@ -163,14 +163,14 @@
|
||||
"dong": "동명동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 동구 장동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 동구 장동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "동구",
|
||||
"dong": "장동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 동구 지산동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 동구 지산동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "동구",
|
||||
"dong": "지산동"
|
||||
},
|
||||
@@ -181,8 +181,8 @@
|
||||
"dong": "학동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 북구 누문동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 북구 누문동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "북구",
|
||||
"dong": "누문동"
|
||||
},
|
||||
@@ -223,14 +223,14 @@
|
||||
"dong": "양산동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 북구 오룡동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 북구 오룡동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "북구",
|
||||
"dong": "오룡동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 북구 오치동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 북구 오치동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "북구",
|
||||
"dong": "오치동"
|
||||
},
|
||||
@@ -247,8 +247,8 @@
|
||||
"dong": "우산동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 북구 운암동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 북구 운암동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "북구",
|
||||
"dong": "운암동"
|
||||
},
|
||||
@@ -289,8 +289,8 @@
|
||||
"dong": "동천동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 서구 매월동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 서구 매월동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "서구",
|
||||
"dong": "매월동"
|
||||
},
|
||||
@@ -301,8 +301,8 @@
|
||||
"dong": "서창동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 서구 쌍촌동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 서구 쌍촌동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "서구",
|
||||
"dong": "쌍촌동"
|
||||
},
|
||||
@@ -325,8 +325,8 @@
|
||||
"dong": "풍암동"
|
||||
},
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 서구 화정동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 서구 화정동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "서구",
|
||||
"dong": "화정동"
|
||||
}
|
||||
@@ -358,24 +358,24 @@
|
||||
],
|
||||
"서봉동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 광산구 서봉동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 광산구 서봉동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "광산구",
|
||||
"dong": "서봉동"
|
||||
}
|
||||
],
|
||||
"소촌동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 광산구 소촌동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 광산구 소촌동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "광산구",
|
||||
"dong": "소촌동"
|
||||
}
|
||||
],
|
||||
"송정동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 광산구 송정동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 광산구 송정동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "광산구",
|
||||
"dong": "송정동"
|
||||
}
|
||||
@@ -428,16 +428,16 @@
|
||||
],
|
||||
"운수동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 광산구 운수동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 광산구 운수동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "광산구",
|
||||
"dong": "운수동"
|
||||
}
|
||||
],
|
||||
"월계동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 광산구 월계동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 광산구 월계동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "광산구",
|
||||
"dong": "월계동"
|
||||
}
|
||||
@@ -452,8 +452,8 @@
|
||||
],
|
||||
"장덕동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 광산구 장덕동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 광산구 장덕동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "광산구",
|
||||
"dong": "장덕동"
|
||||
}
|
||||
@@ -468,32 +468,32 @@
|
||||
],
|
||||
"방림동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 남구 방림동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 남구 방림동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "남구",
|
||||
"dong": "방림동"
|
||||
}
|
||||
],
|
||||
"백운동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 남구 백운동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 남구 백운동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "남구",
|
||||
"dong": "백운동"
|
||||
}
|
||||
],
|
||||
"봉선동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 남구 봉선동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 남구 봉선동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "남구",
|
||||
"dong": "봉선동"
|
||||
}
|
||||
],
|
||||
"송하동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 남구 송하동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 남구 송하동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "남구",
|
||||
"dong": "송하동"
|
||||
}
|
||||
@@ -516,8 +516,8 @@
|
||||
],
|
||||
"주월동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 남구 주월동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 남구 주월동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "남구",
|
||||
"dong": "주월동"
|
||||
}
|
||||
@@ -532,8 +532,8 @@
|
||||
],
|
||||
"계림동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 동구 계림동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 동구 계림동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "동구",
|
||||
"dong": "계림동"
|
||||
}
|
||||
@@ -548,16 +548,16 @@
|
||||
],
|
||||
"장동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 동구 장동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 동구 장동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "동구",
|
||||
"dong": "장동"
|
||||
}
|
||||
],
|
||||
"지산동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 동구 지산동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 동구 지산동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "동구",
|
||||
"dong": "지산동"
|
||||
}
|
||||
@@ -572,8 +572,8 @@
|
||||
],
|
||||
"누문동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 북구 누문동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 북구 누문동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "북구",
|
||||
"dong": "누문동"
|
||||
}
|
||||
@@ -628,16 +628,16 @@
|
||||
],
|
||||
"오룡동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 북구 오룡동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 북구 오룡동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "북구",
|
||||
"dong": "오룡동"
|
||||
}
|
||||
],
|
||||
"오치동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 북구 오치동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 북구 오치동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "북구",
|
||||
"dong": "오치동"
|
||||
}
|
||||
@@ -652,8 +652,8 @@
|
||||
],
|
||||
"운암동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 북구 운암동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 북구 운암동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "북구",
|
||||
"dong": "운암동"
|
||||
}
|
||||
@@ -708,8 +708,8 @@
|
||||
],
|
||||
"매월동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 서구 매월동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 서구 매월동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "서구",
|
||||
"dong": "매월동"
|
||||
}
|
||||
@@ -724,8 +724,8 @@
|
||||
],
|
||||
"쌍촌동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 서구 쌍촌동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 서구 쌍촌동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "서구",
|
||||
"dong": "쌍촌동"
|
||||
}
|
||||
@@ -756,8 +756,8 @@
|
||||
],
|
||||
"화정동": [
|
||||
{
|
||||
"fullName": "전남광주통합특별시(광주) 서구 화정동",
|
||||
"sido": "전남광주통합특별시(광주)",
|
||||
"fullName": "광주광역시 서구 화정동",
|
||||
"sido": "광주광역시",
|
||||
"sigungu": "서구",
|
||||
"dong": "화정동"
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 6.6 MiB |
@@ -3,30 +3,29 @@
|
||||
<!-- 1. 클린 미니멀 프리미엄 네비게이션 헤더 (기본 홈과 동일) -->
|
||||
<AppHeader :siteName="siteName" />
|
||||
|
||||
<!-- 2. 세련된 지역 센터 식별 서브 바 (모던 칩 배너) -->
|
||||
<div class="bg-blue-50/70 border-b border-blue-100/70 py-2.5 px-4">
|
||||
<!-- 2. 시맨틱 브레드크럼 네비게이션 바 (더세이브 nav.bc 구조 동기화) -->
|
||||
<nav class="bc bg-blue-50/70 border-b border-blue-100/70 py-2.5 px-4" aria-label="현재 위치">
|
||||
<div class="max-w-4xl mx-auto flex items-center justify-between flex-wrap gap-2 text-xs">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="inline-flex items-center gap-1 font-bold text-blue-700 bg-white px-2.5 py-0.5 rounded-full border border-blue-200/80 shadow-xs">
|
||||
<i class="fa-solid fa-location-dot text-blue-600 text-[10px]"></i>
|
||||
{{ parsed.shortRegionName }} 센터
|
||||
</span>
|
||||
<span class="text-slate-600 font-medium">
|
||||
{{ parsed.dong }} ({{ parsed.sigungu }}) 관내 초·중·고 1:1 맞춤 전담
|
||||
</span>
|
||||
<div class="flex items-center gap-1.5 text-slate-600 font-medium">
|
||||
<NuxtLink to="/" class="hover:text-blue-600 font-semibold transition-colors">홈</NuxtLink>
|
||||
<span class="text-slate-400">›</span>
|
||||
<span>{{ parsed.dong }} 과외</span>
|
||||
<span class="text-slate-400">›</span>
|
||||
<strong class="font-bold text-blue-700">{{ parsed.shortSido }} {{ parsed.gradeShort }} {{ parsed.subjectName }} 과외</strong>
|
||||
</div>
|
||||
<div class="hidden sm:flex items-center gap-1 text-slate-500 font-medium">
|
||||
<i class="fa-solid fa-shield-check text-emerald-600 text-xs"></i>
|
||||
<span>검증된 전문 선생님 100% 매칭</span>
|
||||
<span>{{ parsed.shortRegionName }} 센터 · 검증된 전문 선생님 100% 매칭</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- 3. 상단 히어로 배너 (H1 태그 포함) -->
|
||||
<!-- 3. 상단 히어로 배너 (H1 -> meta -> H2 -> p 순서) -->
|
||||
<HeroBanner
|
||||
:region="parsed.region"
|
||||
:shortRegionName="parsed.shortRegionName"
|
||||
:grade="parsed.grade"
|
||||
:grade-short="parsed.gradeShort"
|
||||
:subjectName="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -67,6 +66,8 @@
|
||||
<FaqAccordion
|
||||
:regionDong="parsed.dong"
|
||||
:grade="parsed.grade"
|
||||
:gradeShort="parsed.gradeShort"
|
||||
:shortSido="parsed.shortSido"
|
||||
:subjectName="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -74,6 +75,8 @@
|
||||
<FastConsultFocus
|
||||
:regionDong="parsed.dong"
|
||||
:grade="parsed.grade"
|
||||
:gradeShort="parsed.gradeShort"
|
||||
:shortSido="parsed.shortSido"
|
||||
:subjectName="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -81,6 +84,8 @@
|
||||
<SubjectCarousel
|
||||
:regionDong="parsed.dong"
|
||||
:grade="parsed.grade"
|
||||
:gradeShort="parsed.gradeShort"
|
||||
:shortSido="parsed.shortSido"
|
||||
:currentSubject="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -97,13 +102,11 @@
|
||||
:defaultGrade="parsed.grade"
|
||||
:defaultSubject="parsed.subjectName"
|
||||
/>
|
||||
|
||||
<!-- 14. 클린 사이트 푸터 -->
|
||||
<AppFooter />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { parseRouteSlug, getCurriculumBySubject, getAllSubjectsList, getPopularRegions } from '~/utils/dataHelper'
|
||||
import { generateSeoMeta } from '~/utils/seoHelper'
|
||||
@@ -112,28 +115,27 @@ const route = useRoute()
|
||||
const config = useRuntimeConfig()
|
||||
const siteName = config.public?.siteName || '클래스픽'
|
||||
|
||||
// URL 파라미터 파싱
|
||||
const slug = route.params.slug
|
||||
const parsed = parseRouteSlug(slug)
|
||||
// URL 파라미터 파싱 (반응형 computed)
|
||||
const parsed = computed(() => parseRouteSlug(route.params.slug))
|
||||
|
||||
// 커리큘럼 데이터 로드
|
||||
const curriculum = getCurriculumBySubject(parsed.subjectKey)
|
||||
const curriculum = computed(() => getCurriculumBySubject(parsed.value.subjectKey))
|
||||
const allSubjects = getAllSubjectsList()
|
||||
const popularRegions = getPopularRegions(12)
|
||||
|
||||
// 네이버 Yeti 봇 100% 대응 SEO 메타태그 설정
|
||||
const seo = generateSeoMeta(
|
||||
parsed,
|
||||
const seo = computed(() => generateSeoMeta(
|
||||
parsed.value,
|
||||
config.public.siteName,
|
||||
config.public.siteDomain
|
||||
)
|
||||
))
|
||||
|
||||
useHead({
|
||||
title: seo.title,
|
||||
meta: seo.meta,
|
||||
link: seo.link,
|
||||
script: seo.script
|
||||
})
|
||||
useHead(() => ({
|
||||
title: seo.value.title,
|
||||
meta: seo.value.meta,
|
||||
link: seo.value.link,
|
||||
script: seo.value.script
|
||||
}))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<!-- 1. Header (클린 미니멀 프리미엄 네비게이션) -->
|
||||
<header class="bg-white/95 backdrop-blur-md border-b border-slate-200/80 sticky top-0 z-40 w-full transition-all">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6 py-3.5 flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<NuxtLink to="/" class="flex items-center gap-3">
|
||||
<div class="w-9 h-9 rounded-xl bg-blue-600 flex items-center justify-center text-white font-extrabold text-base shadow-sm">
|
||||
C
|
||||
{{ siteName.charAt(0) }}
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-extrabold text-lg sm:text-xl tracking-tight text-slate-900">{{ siteName }}</span>
|
||||
@@ -14,7 +14,7 @@
|
||||
교육청 등록 협력
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<a href="tel:010-5961-5807" class="hidden sm:flex items-center gap-1.5 text-sm font-semibold text-slate-600 hover:text-blue-600 transition">
|
||||
@@ -32,8 +32,8 @@
|
||||
<!-- 2. Main Body -->
|
||||
<main class="w-full pb-20">
|
||||
|
||||
<!-- 히어로 섹션 (AI 스타일 형광/물결 제거, 정제된 모던 에듀테크 캔버스) -->
|
||||
<section class="w-full bg-white border-b border-slate-200/80 pt-12 sm:pt-16 pb-20 px-4 sm:px-6 text-center relative overflow-hidden">
|
||||
<!-- 히어로 섹션 (H1 -> meta -> H2 -> p 순서) -->
|
||||
<section class="hero-section w-full bg-white border-b border-slate-200/80 pt-12 sm:pt-16 pb-20 px-4 sm:px-6 text-center relative overflow-hidden" itemscope itemtype="https://schema.org/EducationalOrganization">
|
||||
|
||||
<!-- 은은한 상단 엠비언트 라이트 (절제된 디자이너 톤) -->
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-blue-50/40 via-transparent to-transparent pointer-events-none"></div>
|
||||
@@ -46,16 +46,22 @@
|
||||
<span>봉선·수완·일곡·첨단 등 광주 전지역 전담 | 서울대·전남대 및 베테랑 강사진 100% 신원 보증</span>
|
||||
</div>
|
||||
|
||||
<!-- 메인 H1 (지역 기반 검색 상위 노출 30자 규격 및 학부모 고의도 롱테일 키워드) -->
|
||||
<h1 class="text-3xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.2] sm:leading-[1.18] mb-4">
|
||||
광주 초·중·고 1:1 맞춤 과외 매칭<br class="hidden sm:inline" />
|
||||
<span class="text-blue-600">검증된 전문 선생님 100% 매칭</span>
|
||||
<!-- 1. 메인 H1 -->
|
||||
<h1 class="text-3xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.2] sm:leading-[1.18] mb-3">
|
||||
광주 중등 수학 과외 · 초·중·고 1:1 맞춤 과외 매칭<br class="hidden sm:inline" />
|
||||
<span class="text-blue-600">내신·수능 성적 향상의 시작</span>
|
||||
</h1>
|
||||
|
||||
<!-- 서브 헤드라인 (비용 시세 비교 + 봉선동 등 광주 학교 기출 분석 + 무료 시범수업) -->
|
||||
<p class="text-sm sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-8">
|
||||
과외 비용·시세 투명 비교부터 무료 시범수업 신청까지.<br class="hidden sm:inline" />
|
||||
봉선·수완·일곡 등 광주 관내 학교별 기출 족보를 완벽 분석하여 <strong>내신 1등급 역전 솔루션</strong>을 제공합니다.
|
||||
<!-- 2. meta (H1 바로 다음 줄) -->
|
||||
<meta itemprop="name" :content="`${siteName} - 광주 중등 수학 과외 · 광주 중등 과외 1:1 매칭`" />
|
||||
<meta itemprop="description" content="광주 중등 수학 과외, 광주 중등 과외부터 초등·고등 국영수사과 1:1 방문·화상 맞춤 과외 매칭 및 과외비 투명 비교" />
|
||||
<meta itemprop="keywords" content="광주 중등 수학 과외, 광주 중등 과외, 광주 고등 수학 과외, 광주 고등 과외, 광주 초등 수학 과외, 광주 초등 과외, 광주 중등 영어 과외, 광주 과외, 봉선동 과외" />
|
||||
<meta itemprop="image" :content="`${siteDomain}/img/math-tutoring.png`" />
|
||||
<link itemprop="url" :href="`${siteDomain}/`" />
|
||||
<!-- 3. H2 (meta 바로 다음 줄) -->
|
||||
<h2 class="hero-subtitle text-base sm:text-lg font-bold text-slate-700 mb-3">광주 중등 과외 · 초등·고등 국영수사과 검증된 전문 선생님 100% 1:1 매칭</h2>
|
||||
<!-- 4. 일반글 p (H2 바로 다음 줄) -->
|
||||
<p class="hero-desc text-sm sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-8">
|
||||
광주 중등 수학 과외 및 광주 중등 과외, 초등·고등 전 과목 과외 비용·시세 투명 비교부터 검증된 전문 선생님 무료 시범수업까지 학생에게 꼭 맞는 1:1 맞춤 수업을 제공합니다.
|
||||
</p>
|
||||
|
||||
<!-- 4대 핵심 신뢰 보증 지표 (Trust Bar) -->
|
||||
@@ -382,54 +388,37 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 6. 자주 묻는 질문 (FAQ) -->
|
||||
<!-- 5-2. 과목별 1:1 맞춤과외 갤러리 캐러셀 -->
|
||||
<SubjectCarousel :regionDong="defaultDong" shortSido="광주" grade="중학생" gradeShort="중등" />
|
||||
|
||||
<!-- 6. 자주 묻는 질문 (FAQ - 네이티브 details/summary 시맨틱 구조) -->
|
||||
<section class="max-w-4xl mx-auto px-4 sm:px-6 py-16">
|
||||
<div class="text-center mb-10">
|
||||
<h2 class="text-2xl font-extrabold text-slate-900">과외 상담 전 자주 묻는 질문</h2>
|
||||
<h2 class="text-2xl font-extrabold text-slate-900">광주 중등 수학 과외 · 광주 중등 과외 자주 묻는 질문</h2>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div
|
||||
<details
|
||||
v-for="(faq, idx) in faqs"
|
||||
:key="idx"
|
||||
class="bg-white border border-slate-200 rounded-xl overflow-hidden"
|
||||
:open="idx === 0"
|
||||
class="qa border border-slate-200 rounded-xl overflow-hidden bg-white shadow-xs group"
|
||||
>
|
||||
<button
|
||||
@click="faq.open = !faq.open"
|
||||
class="w-full text-left px-5 py-4 font-bold text-sm sm:text-base text-slate-900 flex justify-between items-center hover:bg-slate-50 transition"
|
||||
>
|
||||
<summary class="w-full text-left px-5 py-4 font-bold text-sm sm:text-base text-slate-900 cursor-pointer list-none flex justify-between items-center hover:bg-slate-50 transition">
|
||||
<span>{{ faq.q }}</span>
|
||||
<i :class="faq.open ? 'fa-solid fa-chevron-up' : 'fa-solid fa-chevron-down'" class="text-slate-400 text-xs"></i>
|
||||
</button>
|
||||
<div v-show="faq.open" class="px-5 pb-4 text-xs sm:text-sm text-slate-600 border-t border-slate-100 pt-3 leading-relaxed">
|
||||
<i class="fa-solid fa-chevron-down text-slate-400 text-xs transition-transform group-open:rotate-180"></i>
|
||||
</summary>
|
||||
<div class="ans px-5 pb-4 text-xs sm:text-sm text-slate-600 border-t border-slate-100 pt-3 leading-relaxed bg-slate-50/50">
|
||||
{{ faq.a }}
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
<!-- 7. 관내 학년·과목·지역별 내부 연계 허브 (SSR SEO 크롤링 최적화) -->
|
||||
<InternalLinkHub :regionDong="defaultDong" grade="중학생" subjectName="수학" />
|
||||
|
||||
<!-- 7. Footer -->
|
||||
<footer class="bg-slate-900 text-slate-400 text-xs py-10 px-4 sm:px-6">
|
||||
<div class="max-w-5xl mx-auto space-y-4">
|
||||
<div class="flex flex-wrap items-center justify-between gap-4 border-b border-slate-800 pb-4">
|
||||
<span class="text-white font-extrabold text-base">{{ siteName }}</span>
|
||||
<div class="flex gap-4 text-slate-400">
|
||||
<span>이용약관</span>
|
||||
<span>개인정보처리방침</span>
|
||||
<span>과외교습자 등록현황</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="leading-relaxed">
|
||||
{{ siteName }} | 대표번호: 010-5961-5807 | 광주광역시 관내 전문 1:1 맞춤 과외 매칭 및 학습 관리 센터<br />
|
||||
통신판매업 신고 및 개인과외교습자 적법 등록 완료 | 이메일 문의: contact@{{ siteDomain.replace('https://', '') }}
|
||||
</p>
|
||||
<p class="text-slate-500">
|
||||
© 2026 {{ siteName }}. All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
@@ -437,8 +426,10 @@
|
||||
<script setup>
|
||||
import { reactive, ref, onMounted, onUnmounted } from 'vue'
|
||||
|
||||
const siteName = '클래스픽'
|
||||
const siteDomain = 'https://aeseo.store'
|
||||
const config = useRuntimeConfig()
|
||||
const siteName = config.public.siteName || '클래스픽'
|
||||
const siteDomain = config.public.siteDomain || 'https://aeseo.store'
|
||||
const defaultDong = '봉선동'
|
||||
|
||||
const gradeOptions = ['초등학생', '중1', '중2', '중3', '고1', '고2·고3']
|
||||
const subjectOptions = ['수학', '영어', '국어', '과학', '사회/한국사', '전과목 코칭']
|
||||
@@ -531,23 +522,23 @@ function formatPhoneNumber() {
|
||||
|
||||
const faqs = reactive([
|
||||
{
|
||||
q: '무료 시범수업은 어떻게 진행되나요?',
|
||||
a: '신청서 접수 후 광주 전담 매니저가 유선으로 학생의 성향과 목표를 파악한 뒤, 가장 적합한 전문 선생님을 배정해 드립니다. 배정된 선생님이 1:1 방문 또는 화상으로 40~50분간 모의 수업 및 취약점 진단을 무료로 진행하며, 수업 후 계속 진행 여부를 편안하게 결정하실 수 있습니다.',
|
||||
q: '광주 중등 수학 과외 · 광주 중등 과외 무료 시범수업은 어떻게 진행되나요?',
|
||||
a: '광주 중등 수학 과외 및 광주 중등 과외 신청서 접수 후 광주 전담 매니저가 유선으로 학생의 성향과 목표를 파악한 뒤 가장 적합한 광주 초·중·고 과외 전문 선생님을 배정해 드립니다. 배정된 선생님이 1:1 방문 또는 화상으로 40~50분간 모의 수업 및 취약점 진단을 무료로 진행하며, 수업 후 계속 진행 여부를 편안하게 결정하실 수 있습니다.',
|
||||
open: true
|
||||
},
|
||||
{
|
||||
q: '과외 비용 및 시세는 어떻게 되나요?',
|
||||
a: '학년(초등/중등/고등)과 주당 수업 횟수(주 1회, 주 2회 등), 수업 시간(회당 60분~120분)에 따라 교육청 가이드라인에 맞춘 투명한 표준 시세로 책정됩니다. 상담 시 거품 없는 정확한 광주 우리 동네 과외 비용을 안내해 드립니다.',
|
||||
q: '광주 중등 수학 과외 및 광주 초·중·고 과외 비용·시세는 어떻게 되나요?',
|
||||
a: '광주 중등 수학 과외, 광주 중등 과외, 광주 초·중·고 과외 비용은 학년(초등/중등/고등)과 주당 수업 횟수(주 1회, 주 2회 등), 수업 시간(회당 60분~120분)에 따라 교육청 가이드라인에 맞춘 투명한 표준 시세로 책정됩니다. 상담 시 거품 없는 정확한 광주 우리 동네 과외 비용을 안내해 드립니다.',
|
||||
open: false
|
||||
},
|
||||
{
|
||||
q: '선생님 신원과 학력 검증은 어떻게 이루어지나요?',
|
||||
a: '모든 강사진은 주민등록초본, 대학/대학원 재학 및 졸업증명서, 성범죄 경력 조회 등 엄격한 4단계 서류 검증과 교육청 개인과외교습자 신고를 100% 완료한 검증된 전문 선생님입니다.',
|
||||
q: '광주 중등 과외 · 광주 초·중·고 과외 선생님 신원과 학력 검증은 어떻게 이루어지나요?',
|
||||
a: '광주 중등 수학 과외 및 광주 중등 과외 모든 강사진은 주민등록초본, 대학/대학원 재학 및 졸업증명서, 성범죄 경력 조회 등 엄격한 4단계 서류 검증과 교육청 개인과외교습자 신고를 100% 완료한 검증된 광주 초·중·고 과외 전문 선생님입니다.',
|
||||
open: false
|
||||
},
|
||||
{
|
||||
q: '선생님이 아이와 맞지 않으면 어떻게 하나요?',
|
||||
a: '무료 시범수업을 통해 사전에 호흡을 맞출 수 있으며, 정규 수업 진행 중에도 선생님 교체를 희망하시면 추가 비용 없이 100% 만족하실 때까지 새로운 선생님으로 무료 재매칭을 진행해 드립니다.',
|
||||
q: '광주 중등 수학 과외 선생님이 아이와 맞지 않으면 교체가 가능한가요?',
|
||||
a: '광주 중등 수학 과외 및 광주 중등 과외는 무료 시범수업을 통해 사전에 호흡을 맞출 수 있으며, 광주 초·중·고 과외 정규 수업 진행 중에도 선생님 교체를 희망하시면 추가 비용 없이 100% 만족하실 때까지 새로운 선생님으로 무료 재매칭을 진행해 드립니다.',
|
||||
open: false
|
||||
}
|
||||
])
|
||||
@@ -591,46 +582,88 @@ async function handleSubmit() {
|
||||
// SEO 태그 설정 (지역 기반 + 고의도 롱테일 키워드 30~35자 내외 글자 수 준수)
|
||||
// SEO 태그 및 소셜 메타데이터 (네이버/구글 검색 최적화 및 3종 구조화 데이터 JSON-LD)
|
||||
useHead({
|
||||
title: '클래스픽 | 광주 초·중·고 검증된 맞춤 과외 매칭',
|
||||
title: `광주 중등 수학 과외 · 광주 중등 과외 | 초·중·고 1:1 맞춤 과외 ${siteName}`,
|
||||
link: [
|
||||
{ rel: 'canonical', href: 'https://aeseo.store/' }
|
||||
],
|
||||
meta: [
|
||||
{ name: 'robots', content: 'index,follow' },
|
||||
{ name: 'naver-site-verification', content: '48cf582068341a6e4bebde6900b3e0a0e198f4b6' },
|
||||
{ name: 'description', content: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 명문대 및 베테랑 전문 강사진 1:1 맞춤 배정 솔루션' },
|
||||
{ name: 'description', content: `광주 중등 수학 과외, 광주 중등 과외, 봉선동 중등 수학 과외 전문 ${siteName}! 광주 초·중·고 국영수사과 1:1 방문·화상 맞춤 수업, 과외 비용·시세 투명 비교부터 무료 시범수업 신청까지.` },
|
||||
{ name: 'keywords', content: '광주 중등 수학 과외, 광주 중등 과외, 광주 고등 수학 과외, 광주 고등 과외, 광주 초등 수학 과외, 광주 초등 과외, 광주 중등 영어 과외, 광주 고등 영어 과외, 광주 과외, 봉선동 과외, 봉선동 중등 수학 과외' },
|
||||
{ property: 'og:type', content: 'website' },
|
||||
{ property: 'og:site_name', content: '클래스픽' },
|
||||
{ property: 'og:title', content: '클래스픽 | 광주 초·중·고 맞춤 과외 매칭' },
|
||||
{ property: 'og:description', content: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 검증된 전문 선생님 100% 매칭' },
|
||||
{ property: 'og:locale', content: 'ko_KR' },
|
||||
{ property: 'og:site_name', content: siteName },
|
||||
{ property: 'og:title', content: `광주 중등 수학 과외 · 광주 중등 과외 | 초·중·고 1:1 맞춤 과외 ${siteName}` },
|
||||
{ property: 'og:description', content: `광주 중등 수학 과외, 광주 중등 과외, 봉선동 중등 수학 과외 전문 ${siteName}! 과외 비용·시세 투명 비교부터 무료 시범수업 신청까지 검증된 전문 선생님 100% 매칭` },
|
||||
{ property: 'og:url', content: 'https://aeseo.store/' },
|
||||
{ property: 'og:image', content: 'https://aeseo.store/img/og-main.png' },
|
||||
{ property: 'og:image:type', content: 'image/png' },
|
||||
{ property: 'og:image:width', content: '1200' },
|
||||
{ property: 'og:image:height', content: '630' },
|
||||
{ property: 'og:image:alt', content: '광주 중등 수학 과외 · 광주 중등 과외' },
|
||||
{ name: 'twitter:card', content: 'summary_large_image' },
|
||||
{ name: 'twitter:title', content: '클래스픽 | 광주 초·중·고 맞춤 과외 매칭' },
|
||||
{ name: 'twitter:description', content: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 검증된 전문 선생님 100% 매칭' },
|
||||
{ name: 'twitter:title', content: `광주 중등 수학 과외 · 광주 중등 과외 | 초·중·고 1:1 맞춤 과외 ${siteName}` },
|
||||
{ name: 'twitter:description', content: `광주 중등 수학 과외, 광주 중등 과외, 봉선동 중등 수학 과외 전문 ${siteName}! 과외 비용·시세 투명 비교부터 무료 시범수업 신청까지 검증된 전문 선생님 100% 매칭` },
|
||||
{ name: 'twitter:image', content: 'https://aeseo.store/img/og-main.png' }
|
||||
],
|
||||
script: [
|
||||
// 1. EducationalOrganization / LocalBusiness 스키마
|
||||
// 1. @graph (WebSite + WebPage + ImageObject + EducationalOrganization / LocalBusiness)
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': ['EducationalOrganization', 'LocalBusiness'],
|
||||
name: '클래스픽',
|
||||
telephone: '+82-10-5961-5807',
|
||||
url: 'https://aeseo.store/',
|
||||
image: 'https://aeseo.store/img/og-main.png',
|
||||
address: {
|
||||
'@type': 'PostalAddress',
|
||||
streetAddress: '봉선중앙로 123 에듀프라자 3층',
|
||||
addressLocality: '남구',
|
||||
addressRegion: '광주광역시',
|
||||
addressCountry: 'KR'
|
||||
},
|
||||
description: '광주 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관',
|
||||
areaServed: '광주광역시 전지역'
|
||||
'@graph': [
|
||||
{
|
||||
'@type': 'WebSite',
|
||||
'@id': `${siteDomain}/#site`,
|
||||
url: `${siteDomain}/`,
|
||||
name: siteName,
|
||||
inLanguage: 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'WebPage',
|
||||
'@id': `${siteDomain}/#page`,
|
||||
url: `${siteDomain}/`,
|
||||
name: `광주 중등 수학 과외 · 광주 중등 과외 | 초·중·고 1:1 맞춤 과외 ${siteName}`,
|
||||
description: `광주 중등 수학 과외, 광주 중등 과외, 봉선동 중등 수학 과외 전문 ${siteName}! 광주 초·중·고 국영수사과 1:1 방문·화상 맞춤 수업`,
|
||||
isPartOf: { '@id': `${siteDomain}/#site` },
|
||||
primaryImageOfPage: { '@id': `${siteDomain}/#img` },
|
||||
inLanguage: 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'ImageObject',
|
||||
'@id': `${siteDomain}/#img`,
|
||||
url: `${siteDomain}/img/math-tutoring.png`,
|
||||
contentUrl: `${siteDomain}/img/math-tutoring.png`,
|
||||
width: 1080,
|
||||
height: 1080,
|
||||
caption: '광주 중등 수학 과외 · 광주 중등 과외'
|
||||
},
|
||||
{
|
||||
'@type': ['EducationalOrganization', 'LocalBusiness'],
|
||||
name: siteName,
|
||||
telephone: '+82-10-5961-5807',
|
||||
url: `${siteDomain}/`,
|
||||
image: [
|
||||
`${siteDomain}/img/og-main.png`,
|
||||
`${siteDomain}/img/math-tutoring.png`,
|
||||
`${siteDomain}/img/english-tutoring.png`,
|
||||
`${siteDomain}/img/korean-tutoring.png`,
|
||||
`${siteDomain}/img/science-tutoring.png`,
|
||||
`${siteDomain}/img/social-studies-tutoring.png`
|
||||
],
|
||||
address: {
|
||||
'@type': 'PostalAddress',
|
||||
streetAddress: '봉선중앙로 123 에듀프라자 3층',
|
||||
addressLocality: '남구',
|
||||
addressRegion: '광주광역시',
|
||||
addressCountry: 'KR'
|
||||
},
|
||||
description: '광주 중등 수학 과외, 광주 중등 과외 및 광주 초·중·고 1:1 맞춤 과외 전문 교육 기관',
|
||||
areaServed: '광주광역시 전지역'
|
||||
}
|
||||
]
|
||||
})
|
||||
},
|
||||
// 2. FAQPage 스키마
|
||||
@@ -649,50 +682,56 @@ useHead({
|
||||
}))
|
||||
})
|
||||
},
|
||||
// 3. ItemList 과목별 갤러리 섹션 스키마
|
||||
// 3. ItemList 과목별 및 학년별 갤러리 섹션 스키마 (더세이브 최상위 name/url/image + Google Course 리치 결과)
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'ItemList',
|
||||
name: '과목별 1:1 맞춤 과외 프로그램',
|
||||
name: `광주 중등 수학 과외 · 광주 중등 과외 프로그램`,
|
||||
itemListElement: [
|
||||
{
|
||||
{ sub: '수학', grade: '중학생', title: '광주 중등 수학 과외 · 봉선동 중학생 수학과외', desc: '개념 구멍 추적 및 킬러 문항 1:1 완파', img: 'math-tutoring.png' },
|
||||
{ sub: '영어', grade: '중학생', title: '광주 중등 영어 과외 · 봉선동 중학생 영어과외', desc: '교과서·부교재 전 지문 변형 및 서술형 영작', img: 'english-tutoring.png' },
|
||||
{ sub: '국어', grade: '중학생', title: '광주 중등 국어 과외 · 봉선동 중학생 국어과외', desc: '비문학 독해 논리와 교과서 문학 1:1 정밀 분석', img: 'korean-tutoring.png' },
|
||||
{ sub: '과학', grade: '중학생', title: '광주 중등 과학 과외 · 봉선동 중학생 과학과외', desc: '통합과학 원리 이해 및 물화생지 킬러 단원 정복', img: 'science-tutoring.png' },
|
||||
{ sub: '사회', grade: '중학생', title: '광주 중등 사회 과외 · 봉선동 중학생 사회과외', desc: '통합사회·한국사 핵심 흐름 및 사탐 만점 전략', img: 'social-studies-tutoring.png' },
|
||||
{ sub: '수학', grade: '초등학생', title: '광주 초등 수학 과외 · 봉선동 초등학생 수학과외', desc: '초등 기초 연산부터 중등 과정 개념 선행까지 1:1 맞춤 지도', img: 'math-tutoring.png' },
|
||||
{ sub: '수학', grade: '고등학생', title: '광주 고등 수학 과외 · 봉선동 고등학생 수학과외', desc: '광주 관내 고교 기출 족보 분석 및 수능·내신 1등급 완파', img: 'math-tutoring.png' },
|
||||
{ sub: '영어', grade: '고등학생', title: '광주 고등 영어 과외 · 봉선동 고등학생 영어과외', desc: '고등 내신 서술형 영작 첨삭 및 모의고사 1등급 구문 독해', img: 'english-tutoring.png' }
|
||||
].map((item, idx) => {
|
||||
const courseUrl = `${siteDomain}/${encodeURIComponent(defaultDong)}/${encodeURIComponent(item.grade)}/${encodeURIComponent(item.sub)}`
|
||||
const imgUrl = `${siteDomain}/img/${item.img}`
|
||||
return {
|
||||
'@type': 'ListItem',
|
||||
position: 1,
|
||||
name: '수학과외',
|
||||
description: '개념 구멍 추적 및 킬러 문항 1:1 완파',
|
||||
image: 'https://aeseo.store/img/math-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 2,
|
||||
name: '영어과외',
|
||||
description: '교과서·부교재 전 지문 변형 및 서술형 영작',
|
||||
image: 'https://aeseo.store/img/english-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 3,
|
||||
name: '국어과외',
|
||||
description: '비문학 독해 논리와 교과서 문학 1:1 정밀 분석',
|
||||
image: 'https://aeseo.store/img/korean-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 4,
|
||||
name: '과학과외',
|
||||
description: '통합과학 원리 이해 및 물화생지 킬러 단원 정복',
|
||||
image: 'https://aeseo.store/img/science-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 5,
|
||||
name: '사회과외',
|
||||
description: '통합사회·한국사 핵심 흐름 및 사탐 만점 전략',
|
||||
image: 'https://aeseo.store/img/social-studies-tutoring.png'
|
||||
position: idx + 1,
|
||||
name: item.title,
|
||||
url: courseUrl,
|
||||
image: imgUrl,
|
||||
item: {
|
||||
'@type': 'Course',
|
||||
name: item.title,
|
||||
description: item.desc,
|
||||
url: courseUrl,
|
||||
image: imgUrl,
|
||||
provider: {
|
||||
'@type': 'Organization',
|
||||
name: siteName,
|
||||
sameAs: siteDomain
|
||||
},
|
||||
offers: {
|
||||
'@type': 'Offer',
|
||||
category: 'Paid',
|
||||
priceCurrency: 'KRW',
|
||||
availability: 'https://schema.org/InStock',
|
||||
url: courseUrl
|
||||
},
|
||||
hasCourseInstance: {
|
||||
'@type': 'CourseInstance',
|
||||
courseMode: ['onsite', 'online']
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
</defs>
|
||||
<rect width="1200" height="630" fill="url(#bg)"/>
|
||||
<rect x="80" y="80" width="160" height="48" rx="8" fill="#fbbf24"/>
|
||||
<text x="160" y="112" font-family="'Pretendard', sans-serif" font-size="22" font-weight="900" fill="#1e293b" text-anchor="middle">AESEO</text>
|
||||
<text x="160" y="112" font-family="'Pretendard', sans-serif" font-size="22" font-weight="900" fill="#1e293b" text-anchor="middle">클래스픽</text>
|
||||
<text x="80" y="240" font-family="'Pretendard', sans-serif" font-size="56" font-weight="900" fill="#ffffff">우리 동네 초·중·고 1:1 맞춤 과외</text>
|
||||
<text x="80" y="320" font-family="'Pretendard', sans-serif" font-size="68" font-weight="900" fill="#fbbf24">내신 1등급 전문 과외애서</text>
|
||||
<text x="80" y="320" font-family="'Pretendard', sans-serif" font-size="68" font-weight="900" fill="#fbbf24">내신 1등급 전문 클래스픽</text>
|
||||
<text x="80" y="420" font-family="'Pretendard', sans-serif" font-size="30" font-weight="500" fill="#e0e7ff">국어 · 영어 · 수학 · 과학 · 사회 · 수행평가 세특</text>
|
||||
<text x="80" y="480" font-family="'Pretendard', sans-serif" font-size="28" font-weight="700" fill="#ffffff">전국 568개 동 학교별 기출 족보 완벽 분석</text>
|
||||
<rect x="80" y="530" width="340" height="50" rx="25" fill="#10b981"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -83,7 +83,7 @@
|
||||
|
||||
<!-- 성적 상승 그래프 비주얼 -->
|
||||
<text x="35" y="55" fill="#f8fafc" font-size="18" font-weight="800" font-family="'Pretendard', sans-serif">
|
||||
AESEO 성적 향상 지표
|
||||
클래스픽 성적 향상 지표
|
||||
</text>
|
||||
<text x="35" y="80" fill="#94a3b8" font-size="13" font-family="'Pretendard', sans-serif">
|
||||
수강생 평균 2.3등급 수직 상승
|
||||
@@ -96,7 +96,7 @@
|
||||
<text x="32" y="55" fill="#94a3b8" font-size="13" font-weight="700" text-anchor="middle">4등급</text>
|
||||
<text x="32" y="185" fill="#94a3b8" font-size="12" text-anchor="middle">수강 전</text>
|
||||
|
||||
<!-- 과외애서 수강 후 바 -->
|
||||
<!-- 클래스픽 수강 후 바 -->
|
||||
<rect x="95" y="10" width="75" height="150" rx="6" fill="url(#goldGrad)" />
|
||||
<text x="132" y="-5" fill="#f59e0b" font-size="16" font-weight="900" text-anchor="middle">1등급!</text>
|
||||
<text x="132" y="185" fill="#ffffff" font-size="13" font-weight="800" text-anchor="middle">수강 3개월</text>
|
||||
@@ -118,7 +118,7 @@
|
||||
|
||||
<!-- 우측 하단 워터마크 -->
|
||||
<text x="355" y="325" fill="#ffffff" opacity="0.3" font-size="13" font-weight="800" text-anchor="end" font-family="'Pretendard', sans-serif">
|
||||
AESEO TUTORING POSTER
|
||||
클래스픽 TUTORING POSTER
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.2 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.3 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.2 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.2 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 6.6 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.1 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 6.6 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.3 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.1 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.2 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.2 MiB |
@@ -5,22 +5,29 @@
|
||||
<link>https://aeseo.store/</link>
|
||||
<description><![CDATA[광주 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관]]></description>
|
||||
<language>ko</language>
|
||||
<pubDate>Tue, 20 Oct 2026 03:35:57 GMT</pubDate>
|
||||
<lastBuildDate>Tue, 20 Oct 2026 03:35:57 GMT</lastBuildDate>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<lastBuildDate>Wed, 04 Nov 2026 00:47:43 GMT</lastBuildDate>
|
||||
<atom:link href="https://aeseo.store/rss.xml" rel="self" type="application/rss+xml"/>
|
||||
<item>
|
||||
<title><![CDATA[광주 초·중·고 1:1 맞춤 과외 매칭]]></title>
|
||||
<link>https://aeseo.store/</link>
|
||||
<description><![CDATA[봉선·수완 등 광주 전지역 과외 비용 비교 및 시범수업 신청]]></description>
|
||||
<pubDate>Tue, 20 Oct 2026 03:35:57 GMT</pubDate>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<guid>https://aeseo.store/</guid>
|
||||
</item>
|
||||
<item>
|
||||
<title><![CDATA[봉선동 중학생 수학과외 1:1 맞춤 수업]]></title>
|
||||
<link>https://aeseo.store/%EB%B4%89%EC%84%A0%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</link>
|
||||
<description><![CDATA[봉선동 학군 내신 1등급 솔루션]]></description>
|
||||
<pubDate>Tue, 20 Oct 2026 03:35:57 GMT</pubDate>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<guid>https://aeseo.store/%EB%B4%89%EC%84%A0%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</guid>
|
||||
</item>
|
||||
<item>
|
||||
<title><![CDATA[수완동 고등학생 영어과외 1:1 맞춤 수업]]></title>
|
||||
<link>https://aeseo.store/%EC%88%98%EC%99%84%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</link>
|
||||
<description><![CDATA[광산구 수완동 내신 서술형 완벽 대비]]></description>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<guid>https://aeseo.store/%EC%88%98%EC%99%84%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</guid>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
|
||||
@@ -29,8 +29,8 @@ export default defineEventHandler(async (event) => {
|
||||
}
|
||||
|
||||
const webhookUrl = config.discordWebhookUrl || 'https://discordapp.com/api/webhooks/1557204310369116210/9J4y96kmSbYNGtw5OxRgIz7InWcM8o3f8UX0Ad71-IyofwdS7tWmXkF7dj457-I8Ypiu'
|
||||
const siteName = config.public.siteName || '1:1 맞춤과외'
|
||||
const siteDomain = config.public.siteDomain || 'https://aeseo.cloud'
|
||||
const siteName = config.public.siteName || '클래스픽'
|
||||
const siteDomain = config.public.siteDomain || 'https://aeseo.store'
|
||||
|
||||
// 한국 시간 (KST)
|
||||
const now = new Date()
|
||||
@@ -53,7 +53,7 @@ export default defineEventHandler(async (event) => {
|
||||
{
|
||||
title: `[신규 무료 상담 신청 접수] ${finalLocation} - ${finalGrade} (${finalStudentName} 학생)`,
|
||||
description: `**${siteName}** 사이트에서 새로운 1:1 학습 상담 신청이 접수되었습니다.`,
|
||||
color: 0x991b1b, // 신뢰감 있는 딥 레드/네이비
|
||||
color: 0x991b1b,
|
||||
fields: [
|
||||
{
|
||||
name: "[접수 사이트]",
|
||||
|
||||
@@ -4,24 +4,42 @@ export default defineEventHandler((event) => {
|
||||
const config = useRuntimeConfig()
|
||||
const baseUrl = config.public.siteDomain || 'https://aeseo.store'
|
||||
const list = regionsData.list as Array<{ sido: string, sigungu: string, dong: string }>
|
||||
const today = new Date().toISOString().split('T')[0]
|
||||
|
||||
const subjects = ['영어', '수학', '국어', '통합과학', '통합사회']
|
||||
const grades = ['중학생', '고등학생']
|
||||
const subjects = ['수학', '영어', '국어', '과학', '사회']
|
||||
const grades = ['초등학생', '중학생', '고등학생']
|
||||
const subjectImages: Record<string, string> = {
|
||||
'수학': `${baseUrl}/img/math-tutoring.png`,
|
||||
'영어': `${baseUrl}/img/english-tutoring.png`,
|
||||
'국어': `${baseUrl}/img/korean-tutoring.png`,
|
||||
'과학': `${baseUrl}/img/science-tutoring.png`,
|
||||
'사회': `${baseUrl}/img/social-studies-tutoring.png`
|
||||
}
|
||||
|
||||
let xml = `<?xml version="1.0" encoding="UTF-8"?>\n`
|
||||
xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n`
|
||||
xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">\n`
|
||||
|
||||
// 메인
|
||||
xml += ` <url>\n <loc>${baseUrl}/</loc>\n <changefreq>daily</changefreq>\n <priority>1.0</priority>\n </url>\n`
|
||||
xml += ` <url>\n <loc>${baseUrl}/</loc>\n <lastmod>${today}</lastmod>\n <changefreq>daily</changefreq>\n <priority>1.0</priority>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/og-main.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/math-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/english-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/korean-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/science-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/social-studies-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` </url>\n`
|
||||
|
||||
// 568개 동별 주요 과목 및 학년 URL 생성
|
||||
// 동별 주요 과목 및 학년 URL 생성 (슬래시 라우터 구조 통일)
|
||||
list.forEach(r => {
|
||||
// 1. 동 대표
|
||||
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(r.dong)}</loc>\n <changefreq>weekly</changefreq>\n <priority>0.8</priority>\n </url>\n`
|
||||
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(r.dong)}</loc>\n <lastmod>${today}</lastmod>\n <changefreq>weekly</changefreq>\n <priority>0.8</priority>\n <image:image><image:loc>${baseUrl}/img/math-tutoring.png</image:loc></image:image>\n </url>\n`
|
||||
|
||||
// 2. 동-과목-학년 대표 조합
|
||||
subjects.slice(0, 3).forEach(sub => {
|
||||
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(r.dong)}-${encodeURIComponent(grades[0])}-${encodeURIComponent(sub)}</loc>\n <changefreq>weekly</changefreq>\n <priority>0.7</priority>\n </url>\n`
|
||||
// 2. 동/학년/과목 조합
|
||||
grades.forEach(g => {
|
||||
subjects.forEach(sub => {
|
||||
const imgLoc = subjectImages[sub] || `${baseUrl}/img/math-tutoring.png`
|
||||
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(r.dong)}/${encodeURIComponent(g)}/${encodeURIComponent(sub)}</loc>\n <lastmod>${today}</lastmod>\n <changefreq>weekly</changefreq>\n <priority>0.7</priority>\n <image:image><image:loc>${imgLoc}</image:loc></image:image>\n </url>\n`
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -17,10 +17,12 @@ export interface ParsedRouteParams {
|
||||
dong: string
|
||||
shortRegionName: string
|
||||
grade: string
|
||||
gradeShort: string
|
||||
subjectKey: string
|
||||
subjectName: string
|
||||
targetTerm: string
|
||||
fullKeyword: string
|
||||
isRegionOnly?: boolean
|
||||
}
|
||||
|
||||
// 5대 핵심 과목 정의
|
||||
@@ -34,30 +36,34 @@ export const SUBJECTS_MAP: Record<string, { key: string, name: string, badge: st
|
||||
|
||||
// 학년 정의
|
||||
export const GRADES_LIST = [
|
||||
{ key: 'middle', name: '중학생', aliases: ['중학생', '중1', '중2', '중3', '중등'] },
|
||||
{ key: 'high', name: '고등학생', aliases: ['고등학생', '고1', '고2', '고3', '고등', '예비고1'] },
|
||||
{ key: 'elem', name: '초등학생', aliases: ['초등학생', '초등', '초5', '초6'] }
|
||||
{ key: 'middle', name: '중학생', shortName: '중등', aliases: ['중학생', '중1', '중2', '중3', '중등'] },
|
||||
{ key: 'high', name: '고등학생', shortName: '고등', aliases: ['고등학생', '고1', '고2', '고3', '고등', '예비고1', 'N수', '재수'] },
|
||||
{ key: 'elem', name: '초등학생', shortName: '초등', aliases: ['초등학생', '초등', '초1', '초2', '초3', '초4', '초5', '초6'] }
|
||||
]
|
||||
|
||||
// 동 이름으로 지역 검색
|
||||
export function getRegionByDong(dongQuery: string): RegionInfo | null {
|
||||
if (!dongQuery) return null
|
||||
const clean = dongQuery.trim().replace(/동$/, '') // '황금' 또는 '황금동' 모두 매칭
|
||||
const clean = dongQuery.trim().replace(/[동읍면리가]$/, '')
|
||||
const map = regionsData.dongMap as Record<string, RegionInfo[]>
|
||||
|
||||
// 1. 정확 매칭 (황금동)
|
||||
// 1. 정확 매칭
|
||||
if (map[dongQuery] && map[dongQuery].length > 0) {
|
||||
return map[dongQuery][0]
|
||||
}
|
||||
// 2. '동' 붙여서 매칭
|
||||
if (map[dongQuery + '동'] && map[dongQuery + '동'].length > 0) {
|
||||
return map[dongQuery + '동'][0]
|
||||
// 2. '동', '읍', '면' 붙여서 매칭
|
||||
for (const suffix of ['동', '읍', '면']) {
|
||||
if (map[clean + suffix] && map[clean + suffix].length > 0) {
|
||||
return map[clean + suffix][0]
|
||||
}
|
||||
}
|
||||
// 3. 리스트 전체 순회 매칭
|
||||
const found = (regionsData.list as RegionInfo[]).find(r =>
|
||||
r.dong === dongQuery ||
|
||||
r.dong === (dongQuery + '동') ||
|
||||
r.dong.startsWith(clean)
|
||||
r.dong === (clean + '동') ||
|
||||
r.dong === (clean + '읍') ||
|
||||
r.dong === (clean + '면') ||
|
||||
(clean.length >= 2 && r.dong.startsWith(clean))
|
||||
)
|
||||
return found || null
|
||||
}
|
||||
@@ -99,12 +105,6 @@ export function getShortRegionName(sido: string, dong: string, sigungu?: string)
|
||||
}
|
||||
|
||||
// 지능형 URL 슬러그 파서
|
||||
// 지원 예시:
|
||||
// - ['대구광역시', '수성구', '황금동']
|
||||
// - ['대구광역시', '황금동', '중학생', '영어']
|
||||
// - ['황금동', '중학생', '영어']
|
||||
// - ['황금동-중학생-영어']
|
||||
// - '대구광역시-황금동-중학생-영어'
|
||||
export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams {
|
||||
let tokens: string[] = []
|
||||
|
||||
@@ -117,6 +117,7 @@ export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams
|
||||
|
||||
let matchedRegion: RegionInfo | null = null
|
||||
let detectedGrade = '중학생'
|
||||
let detectedGradeShort = '중등'
|
||||
let detectedSubjectKey = 'english'
|
||||
let detectedSubjectName = '영어'
|
||||
let detectedTerm = '과외'
|
||||
@@ -141,30 +142,37 @@ export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams
|
||||
}
|
||||
}
|
||||
|
||||
// 기본값 (568개 타겟 지역 중 첫 번째 기준)
|
||||
// 기본값 (타겟 지역 중 첫 번째 기준)
|
||||
if (!matchedRegion) {
|
||||
matchedRegion = (regionsData.list as RegionInfo[])[0] || {
|
||||
fullName: '경기도 고양시 덕양구 고양동',
|
||||
sido: '경기도',
|
||||
sigungu: '고양시 덕양구',
|
||||
dong: '고양동'
|
||||
fullName: '광주광역시 남구 봉선동',
|
||||
sido: '광주광역시',
|
||||
sigungu: '남구',
|
||||
dong: '봉선동'
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 학년 추출
|
||||
let hasExplicitGrade = false
|
||||
const fullText = tokens.join(' ')
|
||||
for (const g of GRADES_LIST) {
|
||||
if (g.aliases.some(a => fullText.includes(a))) {
|
||||
detectedGrade = g.name
|
||||
detectedGradeShort = g.shortName
|
||||
hasExplicitGrade = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const gradeShort = detectedGradeShort || (detectedGrade === '초등학생' ? '초등' : detectedGrade === '고등학생' ? '고등' : '중등')
|
||||
|
||||
// 4. 과목 추출
|
||||
let hasExplicitSubject = false
|
||||
for (const [key, sub] of Object.entries(SUBJECTS_MAP)) {
|
||||
if (sub.aliases.some(a => fullText.includes(a))) {
|
||||
detectedSubjectKey = key
|
||||
detectedSubjectName = sub.name
|
||||
hasExplicitSubject = true
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -188,10 +196,12 @@ export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams
|
||||
dong: matchedRegion.dong,
|
||||
shortRegionName,
|
||||
grade: detectedGrade,
|
||||
gradeShort,
|
||||
subjectKey: detectedSubjectKey,
|
||||
subjectName: detectedSubjectName,
|
||||
targetTerm: detectedTerm,
|
||||
fullKeyword
|
||||
fullKeyword,
|
||||
isRegionOnly: !hasExplicitGrade && !hasExplicitSubject
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,150 +1,315 @@
|
||||
import type { ParsedRouteParams } from './dataHelper'
|
||||
import type { ParsedRouteParams } from './dataHelper'
|
||||
import { getShortRegionName } from './dataHelper'
|
||||
|
||||
const SUBJECT_IMAGE_MAP: Record<string, string> = {
|
||||
math: '/img/math-tutoring.png',
|
||||
english: '/img/english-tutoring.png',
|
||||
korean: '/img/korean-tutoring.png',
|
||||
science: '/img/science-tutoring.png',
|
||||
social: '/img/social-studies-tutoring.png'
|
||||
}
|
||||
|
||||
const CORE_SUBJECTS = [
|
||||
{ key: 'math', name: '수학', desc: '개념 구멍 추적 및 킬러 문항 1:1 완파', img: '/img/math-tutoring.png' },
|
||||
{ key: 'english', name: '영어', desc: '교과서·부교재 전 지문 변형 및 서술형 영작', img: '/img/english-tutoring.png' },
|
||||
{ key: 'korean', name: '국어', desc: '비문학 독해 논리와 교과서 문학 1:1 정밀 분석', img: '/img/korean-tutoring.png' },
|
||||
{ key: 'science', name: '과학', desc: '통합과학 원리 이해 및 물화생지 킬러 단원 정복', img: '/img/science-tutoring.png' },
|
||||
{ key: 'social', name: '사회', desc: '통합사회·한국사 핵심 흐름 및 사탐 만점 전략', img: '/img/social-studies-tutoring.png' }
|
||||
]
|
||||
|
||||
const CORE_GRADES = ['초등학생', '중학생', '고등학생']
|
||||
|
||||
export function generateSeoMeta(parsed: ParsedRouteParams, siteName = '클래스픽', siteDomain = 'https://aeseo.store') {
|
||||
const { sido, sigungu, dong, shortRegionName, grade, subjectName, targetTerm, fullKeyword } = parsed
|
||||
const { sido, sigungu, dong, shortRegionName, grade, subjectKey, subjectName, isRegionOnly } = parsed
|
||||
|
||||
const shortSido = parsed.shortSido || sido.replace(/특별시|광역시|특별자치시|도/g, '').trim()
|
||||
const gradeShort = parsed.gradeShort || (grade === '초등학생' ? '초등' : grade === '고등학생' ? '고등' : '중등')
|
||||
const regionTitle = shortRegionName || getShortRegionName(sido, dong)
|
||||
const subjectImg = SUBJECT_IMAGE_MAP[subjectKey] || '/img/math-tutoring.png'
|
||||
|
||||
// 학부모 검색 최적화: [지역] [과목]과외 전문 매칭 | [학년] 1:1 방문 맞춤 수업 (공백 포함 30~35자 내외 말줄임 방지)
|
||||
const pageTitle = `${regionTitle} ${subjectName}과외 전문 매칭 | ${grade} 1:1 방문 맞춤 수업`
|
||||
// 검색어 [지역] [초등/중등/고등] [과목] 과외 / [지역] [초등/중등/고등] 과외 완벽 매칭 타이틀
|
||||
const pageTitle = isRegionOnly
|
||||
? `${shortSido} 중등 수학 과외 · ${shortSido} 중등 과외 | ${regionTitle} 초·중·고 1:1 맞춤 과외`
|
||||
: `${shortSido} ${gradeShort} ${subjectName} 과외 · ${regionTitle} ${grade} ${subjectName}과외 | ${shortSido} ${gradeShort} 과외 1:1 매칭`
|
||||
|
||||
// 고의도 검색 및 전환 최적화 메타 디스크립션 (과외 비용 시세 + 학교 기출 분석 + 100% 신원 검증 + 무료 시범수업)
|
||||
const pageDescription = `${regionTitle} ${grade} ${subjectName}과외 전문 매칭. 과외 비용 및 시세 비교부터 무료 시범수업 신청까지. ${dong} 인근 학교별 기출 족보 완벽 분석, 서술형 감점 방지, 검증된 1:1 전문 선생님 100% 매칭.`
|
||||
// 첫 문장이 정확한 타겟 키워드로 시작하는 고의도 메타 디스크립션 (더세이브 동기화)
|
||||
const pageDescription = isRegionOnly
|
||||
? `${shortSido} 중등 수학 과외, ${shortSido} 중등 과외, ${dong} 중등 수학 과외 전문 ${siteName}! ${regionTitle} 초등·중등·고등 국영수사과 1:1 맞춤 과외, 검증된 전문 선생님 무료 시범수업과 과외비 비교를 확인하세요.`
|
||||
: `${shortSido} ${gradeShort} ${subjectName} 과외, ${shortSido} ${gradeShort} 과외, ${dong} ${gradeShort} ${subjectName} 과외 전문 ${siteName}! ${regionTitle} ${grade} ${subjectName} 1:1 방문·화상 맞춤 수업으로 내신·수능 성적 향상을 책임집니다. 과외비 투명 공개 및 무료 시범수업 신청하세요.`
|
||||
|
||||
// 표준 Canonical URL
|
||||
const canonicalUrl = `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(grade)}/${encodeURIComponent(subjectName)}`
|
||||
const pageKeywords = `${shortSido} ${gradeShort} ${subjectName} 과외, ${shortSido} ${gradeShort} 과외, ${dong} ${gradeShort} ${subjectName} 과외, ${dong} ${gradeShort} 과외, ${shortSido}${gradeShort}${subjectName}과외, ${shortSido}${gradeShort}과외, ${shortSido} 중등 수학 과외, ${shortSido} 중등 과외, ${shortSido} 고등 수학 과외, ${shortSido} 초등 수학 과외, ${regionTitle} ${subjectName}과외, ${dong} ${subjectName}과외, ${dong} ${grade} ${subjectName}과외, ${dong}과외, ${sigungu}과외, ${shortSido}과외`
|
||||
|
||||
const jsonLd = {
|
||||
// 표준 Canonical URL (자기참조 분리)
|
||||
const dongUrl = `${siteDomain}/${encodeURIComponent(dong)}`
|
||||
const canonicalUrl = isRegionOnly
|
||||
? dongUrl
|
||||
: `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(grade)}/${encodeURIComponent(subjectName)}`
|
||||
|
||||
// 더세이브 방식 멀티 이미지 배열
|
||||
const orgImages = [
|
||||
`${siteDomain}/img/og-main.png`,
|
||||
`${siteDomain}/img/math-tutoring.png`,
|
||||
`${siteDomain}/img/english-tutoring.png`,
|
||||
`${siteDomain}/img/korean-tutoring.png`,
|
||||
`${siteDomain}/img/science-tutoring.png`,
|
||||
`${siteDomain}/img/social-studies-tutoring.png`
|
||||
]
|
||||
|
||||
// 서브 라우터 캐러셀(ItemList) 항목 구성: 현재 동 기준 5대 과목 + 타 학년 라우터 (중복 제외 총 7개)
|
||||
const carouselCourses: Array<{ name: string, desc: string, url: string, image: string }> = []
|
||||
for (const sub of CORE_SUBJECTS) {
|
||||
const cUrl = `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(grade)}/${encodeURIComponent(sub.name)}`
|
||||
carouselCourses.push({
|
||||
name: `${shortSido} ${gradeShort} ${sub.name} 과외 · ${regionTitle} ${grade} ${sub.name}과외`,
|
||||
desc: `${dong} 관내 학교 내신 기출 분석 및 ${sub.desc}`,
|
||||
url: cUrl,
|
||||
image: `${siteDomain}${sub.img}`
|
||||
})
|
||||
}
|
||||
for (const g of CORE_GRADES) {
|
||||
if (g === grade) continue
|
||||
const gShort = g === '초등학생' ? '초등' : g === '고등학생' ? '고등' : '중등'
|
||||
const cUrl = `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(g)}/${encodeURIComponent(subjectName)}`
|
||||
carouselCourses.push({
|
||||
name: `${shortSido} ${gShort} ${subjectName} 과외 · ${regionTitle} ${g} ${subjectName}과외`,
|
||||
desc: `${dong} ${g} 학생 대상 ${subjectName} 내신·선행 1:1 밀착 지도`,
|
||||
url: cUrl,
|
||||
image: `${siteDomain}${subjectImg}`
|
||||
})
|
||||
}
|
||||
|
||||
const breadcrumbItems = isRegionOnly
|
||||
? [
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 1,
|
||||
'name': '홈',
|
||||
'item': `${siteDomain}/`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 2,
|
||||
'name': `${regionTitle} 과외`,
|
||||
'item': dongUrl
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 1,
|
||||
'name': '홈',
|
||||
'item': `${siteDomain}/`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 2,
|
||||
'name': `${dong} 과외`,
|
||||
'item': dongUrl
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 3,
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 · ${dong} ${grade} ${subjectName}과외`,
|
||||
'item': canonicalUrl
|
||||
}
|
||||
]
|
||||
|
||||
// 블록 1: @graph (WebSite + WebPage + ImageObject + EducationalOrganization + LocalBusiness + Course + BreadcrumbList)
|
||||
const graphJsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@graph': [
|
||||
{
|
||||
'@type': 'WebSite',
|
||||
'@id': `${siteDomain}/#site`,
|
||||
'url': `${siteDomain}/`,
|
||||
'name': siteName,
|
||||
'inLanguage': 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'WebPage',
|
||||
'@id': `${canonicalUrl}#page`,
|
||||
'url': canonicalUrl,
|
||||
'name': pageTitle,
|
||||
'description': pageDescription,
|
||||
'isPartOf': { '@id': `${siteDomain}/#site` },
|
||||
'primaryImageOfPage': { '@id': `${canonicalUrl}#img` },
|
||||
'inLanguage': 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'ImageObject',
|
||||
'@id': `${canonicalUrl}#img`,
|
||||
'url': `${siteDomain}${subjectImg}`,
|
||||
'contentUrl': `${siteDomain}${subjectImg}`,
|
||||
'width': 1080,
|
||||
'height': 1080,
|
||||
'caption': `${shortSido} ${gradeShort} ${subjectName} 과외`
|
||||
},
|
||||
{
|
||||
'@type': 'EducationalOrganization',
|
||||
'name': siteName,
|
||||
'url': siteDomain,
|
||||
'image': orgImages,
|
||||
'telephone': '+82-10-5961-5807',
|
||||
'description': pageDescription,
|
||||
'areaServed': {
|
||||
'@type': 'AdministrativeArea',
|
||||
'name': `${sido} ${sigungu} ${dong}`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Course',
|
||||
'name': `${dong} ${grade} ${subjectName} 1:1 맞춤 과외`,
|
||||
'description': `${dong} 인근 학교 내신 출제 경향 분석 및 ${subjectName} 1등급 도약 커리큘럼`,
|
||||
'provider': {
|
||||
'@type': 'Organization',
|
||||
'name': siteName
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'LocalBusiness',
|
||||
'name': `${regionTitle} 1:1 방문 과외`,
|
||||
'image': `${siteDomain}/img/og-preview.png`,
|
||||
'name': `${shortSido} ${gradeShort} 과외 · ${regionTitle} 1:1 방문 과외`,
|
||||
'image': orgImages,
|
||||
'url': canonicalUrl,
|
||||
'telephone': '+82-10-5961-5807',
|
||||
'priceRange': '₩₩',
|
||||
'address': {
|
||||
'@type': 'PostalAddress',
|
||||
'addressLocality': sido,
|
||||
'addressRegion': sigungu,
|
||||
'addressLocality': sigungu,
|
||||
'addressRegion': sido,
|
||||
'streetAddress': dong,
|
||||
'addressCountry': 'KR'
|
||||
},
|
||||
'areaServed': `${sido} ${sigungu} ${dong}`
|
||||
},
|
||||
{
|
||||
'@type': 'FAQPage',
|
||||
'mainEntity': [
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${dong} ${grade} ${subjectName} 방문 과외와 온라인 화상 과외 중 어떤 것이 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `학생과 학부모님의 선호에 따라 100% 자택 방문 대면 과외 또는 실시간 쌍방향 비대면 화상 과외 중 자유롭게 선택하실 수 있습니다. ${dong} 전 지역 방문 수업이 가능합니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${grade} ${subjectName} 전문 선생님이 학생과 잘 맞지 않으면 교체 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': '네, 1회 무료 모의수업을 통해 사전에 호흡을 맞추며, 정규 수업 시작 후에도 학생의 성향이나 요청에 따라 추가 비용 없이 100% 무료 교체 및 환불 규정을 보장합니다.'
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${grade} ${subjectName} 과외 수업 비용은 어떻게 되나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${grade} 내신 단계, 주당 수업 횟수, 수업 시간(1회 60분/90분/120분)에 따라 표준 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다. 무료 상담 시 상세 견적표를 안내해 드립니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${dong} 학교 중간·기말고사 직전 단기 ${subjectName} 족보 클리닉도 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, 시험 3~4주 전 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${grade} ${subjectName} 단기 속성 킬러 클리닉 프로그램도 상시 운영 중입니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${subjectName} 외에 다른 과목도 함께 상담받을 수 있나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${subjectName} 집중 신청은 물론, 국영수 또는 수탐 복합 패키지로 맞춤 구성하여 전 과목 플래너 관리와 함께 시간표를 편성하실 수 있습니다.`
|
||||
}
|
||||
}
|
||||
]
|
||||
'@type': 'Course',
|
||||
'name': isRegionOnly ? `${shortSido} 중등 수학 과외 · ${regionTitle} 초·중·고 1:1 맞춤 과외` : `${shortSido} ${gradeShort} ${subjectName} 과외 · ${dong} ${grade} ${subjectName} 1:1 맞춤 과외`,
|
||||
'description': `${shortSido} ${gradeShort} ${subjectName} 과외 및 ${dong} 인근 학교 내신 출제 경향 분석, ${subjectName} 1등급 도약 커리큘럼`,
|
||||
'url': canonicalUrl,
|
||||
'image': `${siteDomain}${subjectImg}`,
|
||||
'provider': {
|
||||
'@type': 'Organization',
|
||||
'name': siteName,
|
||||
'sameAs': siteDomain
|
||||
},
|
||||
'offers': {
|
||||
'@type': 'Offer',
|
||||
'category': 'Paid',
|
||||
'priceCurrency': 'KRW',
|
||||
'availability': 'https://schema.org/InStock',
|
||||
'url': canonicalUrl
|
||||
},
|
||||
'hasCourseInstance': {
|
||||
'@type': 'CourseInstance',
|
||||
'courseMode': ['onsite', 'online']
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'BreadcrumbList',
|
||||
'itemListElement': [
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 1,
|
||||
'name': '홈',
|
||||
'item': siteDomain
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 2,
|
||||
'name': sido,
|
||||
'item': `${siteDomain}/${encodeURIComponent(sido)}`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 3,
|
||||
'name': sigungu,
|
||||
'item': `${siteDomain}/${encodeURIComponent(sigungu)}`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 4,
|
||||
'name': `${dong} ${subjectName}`,
|
||||
'item': canonicalUrl
|
||||
}
|
||||
]
|
||||
'itemListElement': breadcrumbItems
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 블록 2: FAQPage 단독 JSON-LD
|
||||
const faqJsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'FAQPage',
|
||||
'mainEntity': [
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외(${dong}), 방문 수업과 화상 수업 모두 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, ${shortSido} ${gradeShort} ${subjectName} 과외 및 ${shortSido} ${gradeShort} 과외는 학생과 학부모님의 선호에 따라 100% 자택 방문 대면 수업 또는 실시간 쌍방향 화상 수업 중 자유롭게 선택하실 수 있으며, ${dong} ${gradeShort} ${subjectName} 과외 전 지역 방문 지도가 가능합니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} 과외 · ${dong} ${gradeShort} ${subjectName} 과외 전문 선생님이 학생과 맞지 않으면 교체 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, ${shortSido} ${gradeShort} ${subjectName} 과외 및 ${shortSido} ${gradeShort} 과외는 1회 무료 시범수업을 통해 사전에 호흡을 맞추며, ${dong} ${gradeShort} ${subjectName} 과외 정규 수업 시작 후에도 추가 비용 없이 100% 무료 선생님 교체 및 환불 규정을 보장합니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 및 ${dong} ${gradeShort} ${subjectName} 과외 수업 비용은 어떻게 되나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${shortSido} ${gradeShort} ${subjectName} 과외와 ${shortSido} ${gradeShort} 과외 비용은 ${grade} 내신 단계, 주당 수업 횟수, 수업 시간(1회 60분/90분/120분)에 따라 표준 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다. ${dong} ${gradeShort} ${subjectName} 과외 무료 상담 시 상세 견적표를 안내해 드립니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${dong} ${gradeShort} ${subjectName} 과외로 중간·기말고사 직전 단기 족보 클리닉도 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, ${shortSido} ${gradeShort} ${subjectName} 과외 및 ${shortSido} ${gradeShort} 과외 전담팀이 시험 3~4주 전 ${dong} 인근 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${dong} ${gradeShort} ${subjectName} 과외 단기 속성 클리닉도 상시 운영 중입니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 외에 국영수사과 다른 과목도 함께 상담받을 수 있나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${shortSido} ${gradeShort} ${subjectName} 과외 집중 신청은 물론, ${shortSido} ${gradeShort} 과외 국영수사과 복합 패키지 및 ${dong} ${gradeShort} ${subjectName} 과외 맞춤형 전 과목 플래너 관리로 시간표를 편성하실 수 있습니다.`
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 블록 3: ItemList 단독 JSON-LD (더세이브 검색결과 가로 이미지 줄 핵심 구조)
|
||||
const itemListJsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'ItemList',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 · ${dong} ${gradeShort} 과외`,
|
||||
'numberOfItems': carouselCourses.length,
|
||||
'itemListElement': carouselCourses.map((c, idx) => ({
|
||||
'@type': 'ListItem',
|
||||
'position': idx + 1,
|
||||
'name': c.name,
|
||||
'url': c.url,
|
||||
'image': c.image,
|
||||
'item': {
|
||||
'@type': 'Course',
|
||||
'name': c.name,
|
||||
'description': c.desc,
|
||||
'url': c.url,
|
||||
'image': c.image,
|
||||
'provider': {
|
||||
'@type': 'Organization',
|
||||
'name': siteName,
|
||||
'sameAs': siteDomain
|
||||
},
|
||||
'offers': {
|
||||
'@type': 'Offer',
|
||||
'category': 'Paid',
|
||||
'priceCurrency': 'KRW',
|
||||
'availability': 'https://schema.org/InStock',
|
||||
'url': c.url
|
||||
},
|
||||
'hasCourseInstance': {
|
||||
'@type': 'CourseInstance',
|
||||
'courseMode': ['onsite', 'online']
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
return {
|
||||
title: pageTitle,
|
||||
meta: [
|
||||
{ name: 'robots', content: 'index,follow' },
|
||||
{ name: 'naver-site-verification', content: '48cf582068341a6e4bebde6900b3e0a0e198f4b6' },
|
||||
{ name: 'description', content: pageDescription },
|
||||
{ name: 'keywords', content: `${dong}과외, ${dong}${subjectName}과외, ${dong}${grade}과외, ${sigungu}과외, ${dong}학원, ${dong}내신대비, ${subjectName}1:1과외` },
|
||||
{ name: 'keywords', content: pageKeywords },
|
||||
{ property: 'og:type', content: 'website' },
|
||||
{ property: 'og:locale', content: 'ko_KR' },
|
||||
{ property: 'og:title', content: pageTitle },
|
||||
{ property: 'og:description', content: pageDescription },
|
||||
{ property: 'og:url', content: canonicalUrl },
|
||||
{ property: 'og:site_name', content: siteName },
|
||||
{ property: 'og:image', content: `${siteDomain}/img/og-preview.png` },
|
||||
{ property: 'og:image', content: `${siteDomain}${subjectImg}` },
|
||||
{ property: 'og:image:type', content: 'image/png' },
|
||||
{ property: 'og:image:width', content: '1200' },
|
||||
{ property: 'og:image:height', content: '630' },
|
||||
{ property: 'og:image:alt', content: `${shortSido} ${gradeShort} ${subjectName} 과외 · ${dong} ${gradeShort} ${subjectName} 과외` },
|
||||
{ name: 'twitter:card', content: 'summary_large_image' },
|
||||
{ name: 'twitter:title', content: pageTitle },
|
||||
{ name: 'twitter:description', content: pageDescription }
|
||||
{ name: 'twitter:description', content: pageDescription },
|
||||
{ name: 'twitter:image', content: `${siteDomain}${subjectImg}` }
|
||||
],
|
||||
link: [
|
||||
{ rel: 'canonical', href: canonicalUrl }
|
||||
@@ -152,7 +317,15 @@ export function generateSeoMeta(parsed: ParsedRouteParams, siteName = '클래스
|
||||
script: [
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(jsonLd)
|
||||
children: JSON.stringify(graphJsonLd)
|
||||
},
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(faqJsonLd)
|
||||
},
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(itemListJsonLd)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,80 +2,83 @@
|
||||
<section class="faq-section">
|
||||
<div class="section-header">
|
||||
<span class="section-badge">궁금한 점을 풀어드립니다</span>
|
||||
<h2 class="section-title">{{ regionDong }} 1:1 과외 자주 묻는 질문</h2>
|
||||
<h2 class="section-title">{{ shortSidoName }} {{ gradeShortName }} {{ subjectName }} 과외 · {{ regionDong }} 1:1 과외 자주 묻는 질문</h2>
|
||||
<p class="section-desc">학부모님들께서 가장 많이 문의하시는 내용을 모았습니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="faq-list">
|
||||
<div
|
||||
<details
|
||||
v-for="(faq, idx) in faqs"
|
||||
:key="idx"
|
||||
class="faq-item"
|
||||
:class="{ active: openIndex === idx }"
|
||||
class="faq-item qa"
|
||||
:open="idx === 0"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="faq-question"
|
||||
@click="toggle(idx)"
|
||||
:aria-expanded="openIndex === idx"
|
||||
>
|
||||
<summary class="faq-question">
|
||||
<span class="q-icon">Q</span>
|
||||
<span class="q-text">{{ faq.q }}</span>
|
||||
<span class="toggle-icon">{{ openIndex === idx ? '▲' : '▼' }}</span>
|
||||
</button>
|
||||
<div v-show="openIndex === idx" class="faq-answer">
|
||||
<span class="toggle-icon">▼</span>
|
||||
</summary>
|
||||
<div class="faq-answer ans">
|
||||
<span class="a-icon">A</span>
|
||||
<p class="a-text">{{ faq.a }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
regionDong: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
shortSido: {
|
||||
type: String,
|
||||
default: '경기'
|
||||
},
|
||||
grade: {
|
||||
type: String,
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
subjectName: {
|
||||
type: String,
|
||||
default: '영어'
|
||||
default: '수학'
|
||||
}
|
||||
})
|
||||
|
||||
const openIndex = ref(0)
|
||||
|
||||
const toggle = (idx) => {
|
||||
openIndex.value = openIndex.value === idx ? -1 : idx
|
||||
}
|
||||
const shortSidoName = computed(() => props.shortSido || '경기')
|
||||
const gradeShortName = computed(() => {
|
||||
if (props.gradeShort) return props.gradeShort
|
||||
return (props.grade || '').includes('초등') ? '초등' : (props.grade || '').includes('고등') ? '고등' : '중등'
|
||||
})
|
||||
|
||||
const faqs = computed(() => [
|
||||
{
|
||||
q: `${props.regionDong} ${props.grade} ${props.subjectName} 방문 과외와 온라인 화상 과외 중 어떤 것이 가능한가요?`,
|
||||
a: `학생과 학부모님의 선호에 따라 100% 자택 방문 대면 과외 또는 실시간 쌍방향 비대면 화상 과외 중 자유롭게 선택하실 수 있습니다. ${props.regionDong} 전 지역 방문 수업이 가능합니다.`
|
||||
q: `${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외(${props.regionDong}), 방문 수업과 온라인 화상 수업 모두 가능한가요?`,
|
||||
a: `네, ${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외 및 ${shortSidoName.value} ${gradeShortName.value} 과외는 학생과 학부모님의 선호에 따라 ${props.regionDong} 100% 자택 방문 대면 과외 또는 실시간 쌍방향 화상 과외 중 자유롭게 선택하실 수 있습니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.grade} ${props.subjectName} 전문 선생님이 학생과 잘 맞지 않으면 교체 가능한가요?`,
|
||||
a: '네, 1회 무료 모의수업을 통해 사전에 호흡을 맞추며, 정규 수업 시작 후에도 학생의 성향이나 요청에 따라 추가 비용 없이 100% 무료 교체 및 환불 규정을 보장합니다.'
|
||||
q: `${shortSidoName.value} ${gradeShortName.value} 과외 및 ${props.regionDong} ${gradeShortName.value} ${props.subjectName} 과외 선생님이 학생과 맞지 않으면 교체 가능한가요?`,
|
||||
a: `네, ${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외는 1회 무료 시범수업을 통해 사전에 호흡을 맞추며, 정규 수업 시작 후에도 학생 성향이나 요청에 따라 추가 비용 없이 100% 무료 교체 및 환불 규정을 보장합니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.grade} ${props.subjectName} 과외 수업 비용은 어떻게 되나요?`,
|
||||
a: `${props.grade} 내신 단계, 주당 수업 횟수, 수업 시간(1회 60분/90분/120분)에 따라 표준 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다. 무료 상담 시 상세 견적표를 안내해 드립니다.`
|
||||
q: `${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외(${props.regionDong} ${props.grade} ${props.subjectName}과외) 수업 비용은 어떻게 되나요?`,
|
||||
a: `${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외 및 ${shortSidoName.value} ${gradeShortName.value} 과외 수업료는 ${props.grade} 내신 단계, 주당 횟수, 수업 시간(60분/90분/120분)에 따라 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.regionDong} 학교 중간·기말고사 직전 단기 ${props.subjectName} 족보 클리닉도 가능한가요?`,
|
||||
a: `네, 시험 3~4주 전 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${props.grade} ${props.subjectName} 단기 속성 킬러 클리닉 프로그램도 상시 운영 중입니다.`
|
||||
q: `${props.regionDong} 학교 중간·기말고사 대비 ${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외 단기 족보 클리닉도 가능한가요?`,
|
||||
a: `네, 시험 3~4주 전 ${props.regionDong} 인근 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외 단기 속성 킬러 클리닉 프로그램도 상시 운영 중입니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.subjectName} 외에 다른 과목도 함께 상담받을 수 있나요?`,
|
||||
a: `${props.subjectName} 집중 신청은 물론, 국영수 또는 수탐 복합 패키지로 맞춤 구성하여 전 과목 플래너 관리와 함께 시간표를 편성하실 수 있습니다.`
|
||||
q: `${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외 외에 다른 과목도 함께 ${shortSidoName.value} ${gradeShortName.value} 과외 상담을 받을 수 있나요?`,
|
||||
a: `${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외 집중 신청은 물론, 국영수 또는 수탐 복합 ${shortSidoName.value} ${gradeShortName.value} 과외 패키지로 맞춤 구성하여 전 과목 플래너 관리와 함께 시간표를 편성하실 수 있습니다.`
|
||||
}
|
||||
])
|
||||
</script>
|
||||
@@ -143,11 +146,16 @@ const faqs = computed(() => [
|
||||
border: none;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
font-size: clamp(0.9rem, 2.2vw, 1.02rem);
|
||||
font-weight: 800;
|
||||
color: var(--text-color, #0f172a);
|
||||
}
|
||||
|
||||
.faq-question::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.q-icon {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
@@ -172,6 +180,11 @@ const faqs = computed(() => [
|
||||
font-size: 0.8rem;
|
||||
color: #94a3b8;
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.faq-item[open] .toggle-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.faq-answer {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 네이버 5개 멀티 썸네일 스니펫 및 상담 링크 매칭용 5개 리스트 -->
|
||||
<!-- 네이버 5개 멀티 썸네일 스니펫 및 상담 링크 매칭용 가로 5열 캐러셀 리스트 -->
|
||||
<div class="focus-grid">
|
||||
<a
|
||||
v-for="(item, idx) in programList"
|
||||
@@ -21,27 +21,29 @@
|
||||
class="focus-card"
|
||||
:title="`${item.title} 상담 신청`"
|
||||
>
|
||||
<div class="focus-thumb-wrap">
|
||||
<img
|
||||
:src="item.image"
|
||||
:alt="`${item.title} 1:1 맞춤 지도`"
|
||||
width="500"
|
||||
height="500"
|
||||
loading="lazy"
|
||||
class="focus-img"
|
||||
/>
|
||||
<span class="step-tag">STEP 0{{ idx + 1 }}</span>
|
||||
</div>
|
||||
|
||||
<div class="focus-info">
|
||||
<div class="focus-item-tag">{{ item.tag }}</div>
|
||||
<strong class="focus-item-title">{{ item.title }}</strong>
|
||||
<p class="focus-item-desc">{{ item.desc }}</p>
|
||||
<div class="focus-cta-link">
|
||||
<span>1:1 상담 예약</span>
|
||||
<span class="arrow-sym">→</span>
|
||||
<figure class="focus-figure m-0 flex flex-col flex-1">
|
||||
<div class="focus-thumb-wrap">
|
||||
<img
|
||||
:src="item.image"
|
||||
:alt="item.title"
|
||||
width="1080"
|
||||
height="1080"
|
||||
decoding="async"
|
||||
loading="eager"
|
||||
class="focus-img"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<figcaption class="focus-info">
|
||||
<div class="focus-item-tag">{{ item.tag }}</div>
|
||||
<h3 class="focus-item-title m-0">{{ item.title }}</h3>
|
||||
<p class="focus-item-desc">{{ item.desc }}</p>
|
||||
<div class="focus-cta-link">
|
||||
<span>1:1 상담 예약</span>
|
||||
<span class="arrow-sym">→</span>
|
||||
</div>
|
||||
</figcaption>
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -56,6 +58,14 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
shortSido: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
subjectName: {
|
||||
type: String,
|
||||
default: '수학'
|
||||
@@ -78,7 +88,7 @@ const displaySubject = computed(() => {
|
||||
return props.subjectName || '수학'
|
||||
})
|
||||
|
||||
// 초등 vs 중등/고등 5개 항목 분기
|
||||
// 초등 vs 중등/고등 5개 항목 분기 (실사 PNG 5종 적용)
|
||||
const programList = computed(() => {
|
||||
const dong = props.regionDong ? `${props.regionDong} ` : ''
|
||||
const sub = displaySubject.value
|
||||
@@ -90,31 +100,31 @@ const programList = computed(() => {
|
||||
tag: '개념 완성',
|
||||
title: `${dong}초등 ${sub}과외 - 기초학습`,
|
||||
desc: '개념 쏙쏙 이해와 튼튼한 연산 기본기 완성',
|
||||
image: '/images/focus/elem-1-basic.svg'
|
||||
image: '/img/math-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '학습 코칭',
|
||||
title: `${dong}초등 ${sub}과외 - 공부방법`,
|
||||
desc: '스스로 원리를 깨우치는 올바른 문제 해결력',
|
||||
image: '/images/focus/elem-2-method.svg'
|
||||
image: '/img/english-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '밀착 피드백',
|
||||
title: `${dong}초등 ${sub}과외 - 숙제검사`,
|
||||
desc: '매일 1:1 오답 점검과 꼼꼼한 피드백 클리닉',
|
||||
image: '/images/focus/elem-3-homework.svg'
|
||||
image: '/img/korean-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '자기주도',
|
||||
title: `${dong}초등 ${sub}과외 - 공부습관`,
|
||||
desc: '매일 스스로 책상에 앉는 주도적 학습 루틴',
|
||||
image: '/images/focus/elem-4-habit.svg'
|
||||
image: '/img/science-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '상위권 도약',
|
||||
title: `${dong}초등 ${sub}과외 - 중등대비`,
|
||||
desc: '중학교 내신 서술형과 심화 개념 선행 마스터',
|
||||
image: '/images/focus/elem-5-middleprep.svg'
|
||||
image: '/img/social-studies-tutoring.png'
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -125,31 +135,31 @@ const programList = computed(() => {
|
||||
tag: '기출 정복',
|
||||
title: `${dong}${grd} 중간고사 ${sub}과외`,
|
||||
desc: '학교별 기출 족보 완벽 분석 및 서술형 킬러 대비',
|
||||
image: '/images/focus/sec-1-midterm.svg'
|
||||
image: '/img/math-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '학기말 총력',
|
||||
title: `${dong}${grd} 기말고사 ${sub}과외`,
|
||||
desc: '전 범위 오답 분석 및 취약 유형 완벽 클리닉',
|
||||
image: '/images/focus/sec-2-final.svg'
|
||||
image: '/img/english-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '수능·전국연합',
|
||||
title: `${dong}${grd} 모의고사 ${sub}과외`,
|
||||
desc: '수능형 사고력 확장 및 실전 시간 배분 특훈',
|
||||
image: '/images/focus/sec-3-mock.svg'
|
||||
image: '/img/korean-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '내신 만점',
|
||||
title: `${dong}${grd} 수행평가 ${sub}과외`,
|
||||
desc: '조건 감점 0점화 및 과제·보고서 완벽 케어',
|
||||
image: '/images/focus/sec-4-assessment.svg'
|
||||
image: '/img/science-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '1등급 집중',
|
||||
title: `${dong}${grd} 내신대비 ${sub}과외`,
|
||||
desc: '관내 교과서·부교재 적중 1:1 맞춤 지도',
|
||||
image: '/images/focus/sec-5-schoolprep.svg'
|
||||
image: '/img/social-studies-tutoring.png'
|
||||
}
|
||||
]
|
||||
})
|
||||
@@ -202,10 +212,10 @@ const programList = computed(() => {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 5열 카드 그리드 */
|
||||
/* 데스크톱: 가로 1열 5칸 균등 그리드 */
|
||||
.focus-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
grid-template-columns: repeat(5, minmax(180px, 1fr));
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
@@ -313,52 +323,22 @@ const programList = computed(() => {
|
||||
transform: translateX(3px);
|
||||
}
|
||||
|
||||
/* 태블릿 및 모바일 반응형 */
|
||||
@media (max-width: 960px) {
|
||||
/* 태블릿 및 모바일 반응형: 가로 스크롤 캐러셀 유지 */
|
||||
@media (max-width: 1024px) {
|
||||
.focus-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.focus-grid {
|
||||
grid-template-columns: 1fr;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x mandatory;
|
||||
gap: 12px;
|
||||
padding-bottom: 12px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.focus-card {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.focus-thumb-wrap {
|
||||
width: 105px;
|
||||
height: 105px;
|
||||
aspect-ratio: 1 / 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.focus-info {
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.focus-item-title {
|
||||
font-size: 0.88rem;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.focus-item-desc {
|
||||
font-size: 0.74rem;
|
||||
margin-bottom: 6px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.focus-cta-link {
|
||||
padding-top: 4px;
|
||||
font-size: 0.72rem;
|
||||
flex: 0 0 220px;
|
||||
scroll-snap-align: start;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<header class="hero-banner-clean bg-white border-b border-slate-200/80 pt-10 sm:pt-14 pb-14 sm:pb-18 px-4 sm:px-6 relative overflow-hidden text-center">
|
||||
<section class="hero-banner hero-banner-clean bg-white border-b border-slate-200/80 pt-10 sm:pt-14 pb-14 sm:pb-18 px-4 sm:px-6 relative overflow-hidden text-center" itemscope itemtype="https://schema.org/Course">
|
||||
|
||||
<!-- 은은한 상단 엠비언트 라이트 -->
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-blue-50/40 via-transparent to-transparent pointer-events-none"></div>
|
||||
@@ -12,16 +12,20 @@
|
||||
<span>{{ region.dong }} 학군 전담 | 서울대·연고대 및 베테랑 강사진 100% 신원 보증</span>
|
||||
</div>
|
||||
|
||||
<!-- SEO 메인 H1 (사용자 지정 롱테일 조합형: [지역] + [학년] + [과목]과외 + 검증된 전문 선생님 100% 매칭) -->
|
||||
<h1 class="text-2xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.22] sm:leading-[1.18] mb-4">
|
||||
<span>{{ displayRegionName }} {{ grade }} {{ subjectName }}과외</span><br />
|
||||
<span class="text-blue-600">우리 아이 맞춤 검증된 전문 선생님 100% 매칭</span>
|
||||
<!-- 네이버 상위 노출 순서: 1. H1 ➔ 2. meta ➔ 3. H2 ➔ 4. 일반글 P -->
|
||||
<h1 itemprop="headline" class="text-2xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.22] sm:leading-[1.18] mb-3">
|
||||
<span class="highlight text-blue-600">{{ shortSidoName }} {{ gradeShortName }} {{ subjectName }} 과외 · {{ region.dong }} {{ grade }} {{ subjectName }}과외</span><br />
|
||||
1:1 맞춤 학습으로 성적 역전!
|
||||
</h1>
|
||||
|
||||
<!-- 서브 카피 (비용 시세 비교 + 학교 기출 분석 + 무료 시범수업 신뢰 트리거) -->
|
||||
<p class="text-xs sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-7">
|
||||
{{ region.dong }} 인근 학교별 기출 분석부터 과외 비용·시세 비교, 취약 개념 클리닉까지.<br class="hidden sm:inline" />
|
||||
직접 수업받아보고 결정하는 <strong>1:1 무료 방문·화상 시범수업</strong>을 신청하세요.
|
||||
<meta itemprop="name" :content="`${shortSidoName} ${gradeShortName} ${subjectName} 과외 · ${shortSidoName} ${gradeShortName} 과외 (${region.dong})`" />
|
||||
<meta itemprop="description" :content="`${shortSidoName} ${gradeShortName} ${subjectName} 과외 및 ${shortSidoName} ${gradeShortName} 과외 전문 매칭. ${displayRegionName} ${grade} ${subjectName} 1:1 방문·화상 맞춤 수업`" />
|
||||
<meta itemprop="keywords" :content="`${shortSidoName} ${gradeShortName} ${subjectName} 과외, ${shortSidoName} ${gradeShortName} 과외, ${region.dong} ${gradeShortName} ${subjectName} 과외, ${region.dong} ${gradeShortName} 과외, ${displayRegionName} ${grade} ${subjectName}과외`" />
|
||||
<meta itemprop="image" content="/img/math-tutoring.png" />
|
||||
<h2 class="hero-subtitle">
|
||||
{{ shortSidoName }} {{ gradeShortName }} 과외 · {{ displayRegionName }} {{ gradeShortName }} {{ subjectName }} 과외 검증된 전문 선생님 1:1 매칭
|
||||
</h2>
|
||||
<p class="sub-headline text-xs sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-7">
|
||||
{{ shortSidoName }} {{ gradeShortName }} {{ subjectName }} 과외 및 {{ shortSidoName }} {{ gradeShortName }} 과외를 찾으시는 학부모님을 위해 {{ region.dong }} 인근 학교별 기출 족보 분석부터 개인별 취약 개념 완벽 보완, 투명한 과외비 안내와 무료 시범수업까지 1:1 밀착 커리큘럼을 제공합니다.
|
||||
</p>
|
||||
|
||||
<!-- 4대 핵심 신뢰 지표 바 -->
|
||||
@@ -84,15 +88,15 @@
|
||||
|
||||
<!-- 태그 목록 -->
|
||||
<div class="flex justify-center flex-wrap gap-1.5">
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ shortSidoName }}{{ gradeShortName }}{{ subjectName }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ shortSidoName }}{{ gradeShortName }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ region.dong }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ region.dong }}{{ subjectName }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ grade }}내신대비</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#과외비용시세</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#1대1무료시범수업</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</header>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -111,12 +115,26 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
subjectName: {
|
||||
type: String,
|
||||
default: '수학'
|
||||
}
|
||||
})
|
||||
|
||||
const shortSidoName = computed(() => {
|
||||
const s = (props.region?.sido || '').replace(/특별시|광역시|특별자치시|도/g, '').trim()
|
||||
return s || '경기'
|
||||
})
|
||||
|
||||
const gradeShortName = computed(() => {
|
||||
if (props.gradeShort) return props.gradeShort
|
||||
return props.grade === '초등학생' ? '초등' : props.grade === '고등학생' ? '고등' : '중등'
|
||||
})
|
||||
|
||||
const noticeIdx = ref(0)
|
||||
let timer = null
|
||||
|
||||
@@ -171,4 +189,12 @@ const displayRegionName = computed(() => {
|
||||
.hero-banner-clean {
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-size: 1.15rem;
|
||||
font-weight: 700;
|
||||
color: #334155;
|
||||
margin-bottom: 0.75rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -116,15 +116,15 @@ const nearbyDongs = computed(() => {
|
||||
}
|
||||
|
||||
// 만약 동일 구의 동이 부족하면 전체에서 다른 동 가져오기
|
||||
if (candidates.length < 5) {
|
||||
if (candidates.length < 12) {
|
||||
const others = allList
|
||||
.filter(r => r.dong !== curDong && !candidates.includes(r.dong))
|
||||
.map(r => r.dong)
|
||||
candidates = [...candidates, ...others]
|
||||
}
|
||||
|
||||
// 중복 제거 후 6개 반환
|
||||
return Array.from(new Set(candidates)).slice(0, 6)
|
||||
// 중복 제거 후 12개 반환
|
||||
return Array.from(new Set(candidates)).slice(0, 12)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 2 - 2 - 1 그리드 정렬 레이아웃 -->
|
||||
<!-- 가로 1열 5칸 캐러셀 레이아웃 -->
|
||||
<div class="subject-grid-221">
|
||||
<div
|
||||
v-for="(item, idx) in subjectList"
|
||||
@@ -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"
|
||||
class="subject-img"
|
||||
loading="lazy"
|
||||
loading="eager"
|
||||
fetchpriority="high"
|
||||
/>
|
||||
<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,13 +88,13 @@
|
||||
<!-- 모달 좌측: 고해상도 생성 이미지 원본 -->
|
||||
<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} 과외`"
|
||||
width="1080"
|
||||
height="1080"
|
||||
decoding="async"
|
||||
class="modal-main-img"
|
||||
/>
|
||||
<span class="modal-img-badge">{{ selectedItem.tag }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 모달 우측: 상세 설명 및 액션 버튼 -->
|
||||
@@ -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({
|
||||
@@ -156,9 +157,17 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
shortSido: {
|
||||
type: String,
|
||||
default: '경기'
|
||||
},
|
||||
grade: {
|
||||
type: String,
|
||||
default: '중·고등'
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
currentSubject: {
|
||||
type: String,
|
||||
@@ -167,15 +176,21 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const defaultDong = '정자동'
|
||||
const defaultSido = '경기'
|
||||
const computedGradeShort = computed(() => {
|
||||
if (props.gradeShort) return props.gradeShort
|
||||
return (props.grade || '').includes('초등') ? '초등' : (props.grade || '').includes('고등') ? '고등' : '중등'
|
||||
})
|
||||
|
||||
const config = useRuntimeConfig()
|
||||
const siteDomain = config.public?.siteDomain || 'https://aeseo.cloud'
|
||||
const siteDomain = config.public?.siteDomain || 'https://aeseo.shop'
|
||||
|
||||
// 5대 핵심 과목 (2 2 1 순서 배치)
|
||||
// 5대 핵심 과목 (가로 1열 5칸 캐러셀 배치)
|
||||
const subjectList = [
|
||||
// 1행: 수학, 영어
|
||||
{
|
||||
name: '수학과외',
|
||||
keyName: '수학',
|
||||
subjectKey: 'math',
|
||||
tag: '인기 1위',
|
||||
image: `${siteDomain}/img/math-tutoring.png`,
|
||||
@@ -190,6 +205,7 @@ const subjectList = [
|
||||
},
|
||||
{
|
||||
name: '영어과외',
|
||||
keyName: '영어',
|
||||
subjectKey: 'english',
|
||||
tag: '내신 필수',
|
||||
image: `${siteDomain}/img/english-tutoring.png`,
|
||||
@@ -205,6 +221,7 @@ const subjectList = [
|
||||
// 2행: 국어, 과학
|
||||
{
|
||||
name: '국어과외',
|
||||
keyName: '국어',
|
||||
subjectKey: 'korean',
|
||||
tag: '문해력 완성',
|
||||
image: `${siteDomain}/img/korean-tutoring.png`,
|
||||
@@ -219,6 +236,7 @@ const subjectList = [
|
||||
},
|
||||
{
|
||||
name: '과학과외',
|
||||
keyName: '과학',
|
||||
subjectKey: 'science',
|
||||
tag: '통합과학',
|
||||
image: `${siteDomain}/img/science-tutoring.png`,
|
||||
@@ -234,6 +252,7 @@ const subjectList = [
|
||||
// 3행: 사회 (1개 단독 센터 정렬)
|
||||
{
|
||||
name: '사회과외',
|
||||
keyName: '사회',
|
||||
subjectKey: 'social',
|
||||
tag: '통합사회',
|
||||
image: `${siteDomain}/img/social-studies-tutoring.png`,
|
||||
@@ -304,8 +323,9 @@ const applyWithSubject = (subjectName) => {
|
||||
|
||||
// 해당 과목 전용 페이지 URL 생성 (NuxtLink 바인딩용)
|
||||
const getSubjectPageUrl = (subjectKey) => {
|
||||
const dong = props.regionDong || '서울'
|
||||
const grade = props.grade || '중학생'
|
||||
const dong = props.regionDong || '수내동'
|
||||
const validGrades = ['초등학생', '중학생', '고등학생']
|
||||
const grade = validGrades.includes(props.grade) ? props.grade : '중학생'
|
||||
const subMap = {
|
||||
math: '수학',
|
||||
english: '영어',
|
||||
@@ -398,31 +418,29 @@ onUnmounted(() => {
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
/* 2 - 2 - 1 그리드 레이아웃 */
|
||||
/* 데스크톱: 가로 1열 5칸 균등 그리드 */
|
||||
.subject-grid-221 {
|
||||
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;
|
||||
grid-column: auto;
|
||||
width: 100%;
|
||||
max-width: calc(50% - 10px);
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.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);
|
||||
@@ -459,14 +477,14 @@ onUnmounted(() => {
|
||||
|
||||
.subject-tag {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
left: 14px;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
background: rgba(15, 23, 42, 0.85);
|
||||
backdrop-filter: blur(4px);
|
||||
color: #ffffff;
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 800;
|
||||
padding: 4px 12px;
|
||||
padding: 3px 10px;
|
||||
border-radius: 9999px;
|
||||
z-index: 2;
|
||||
}
|
||||
@@ -490,9 +508,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 +525,7 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.card-info {
|
||||
padding: 18px 20px;
|
||||
padding: 14px 14px 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
@@ -516,59 +534,68 @@ 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: 1.05rem;
|
||||
font-weight: 800;
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.sub-grade {
|
||||
font-size: 0.78rem;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
color: #64748b;
|
||||
background: #f1f5f9;
|
||||
padding: 2px 8px;
|
||||
padding: 2px 7px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.card-subject-desc {
|
||||
font-size: 0.85rem;
|
||||
font-size: 0.8rem;
|
||||
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.78rem;
|
||||
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: 9px;
|
||||
}
|
||||
|
||||
/* 모바일 반응형 대응 */
|
||||
@media (max-width: 640px) {
|
||||
/* 태블릿/모바일: 가로 스크롤 캐러셀 */
|
||||
@media (max-width: 1024px) {
|
||||
.subject-grid-221 {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x mandatory;
|
||||
gap: 12px;
|
||||
padding-bottom: 12px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
|
||||
.gallery-card {
|
||||
flex: 0 0 220px;
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
|
||||
.card-item-5 {
|
||||
grid-column: auto;
|
||||
max-width: 100%;
|
||||
justify-self: stretch;
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,30 +3,32 @@
|
||||
<!-- 1. 클린 미니멀 프리미엄 네비게이션 헤더 (기본 홈과 동일) -->
|
||||
<AppHeader :siteName="siteName" />
|
||||
|
||||
<!-- 2. 세련된 지역 센터 식별 서브 바 (모던 칩 배너) -->
|
||||
<div class="bg-blue-50/70 border-b border-blue-100/70 py-2.5 px-4">
|
||||
<!-- 2. 더세이브 방식 시맨틱 브레드크럼 및 지역 센터 식별 서브 바 -->
|
||||
<nav class="bc bg-blue-50/70 border-b border-blue-100/70 py-2.5 px-4" aria-label="현재 위치">
|
||||
<div class="max-w-4xl mx-auto flex items-center justify-between flex-wrap gap-2 text-xs">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-1.5 flex-wrap text-slate-600">
|
||||
<NuxtLink to="/" class="font-semibold text-blue-700 hover:underline">홈</NuxtLink>
|
||||
<span class="text-slate-400">›</span>
|
||||
<NuxtLink :to="`/${encodeURIComponent(parsed.dong)}`" class="hover:underline">{{ parsed.dong }} 과외</NuxtLink>
|
||||
<span class="text-slate-400">›</span>
|
||||
<strong class="font-bold text-slate-900">{{ parsed.shortSido }} {{ parsed.gradeShort }} {{ parsed.subjectName }} 과외</strong>
|
||||
</div>
|
||||
<div class="hidden sm:flex items-center gap-1.5 text-slate-500 font-medium">
|
||||
<span class="inline-flex items-center gap-1 font-bold text-blue-700 bg-white px-2.5 py-0.5 rounded-full border border-blue-200/80 shadow-xs">
|
||||
<i class="fa-solid fa-location-dot text-blue-600 text-[10px]"></i>
|
||||
{{ parsed.shortRegionName }} 센터
|
||||
</span>
|
||||
<span class="text-slate-600 font-medium">
|
||||
{{ parsed.dong }} ({{ parsed.sigungu }}) 관내 초·중·고 1:1 맞춤 전담
|
||||
</span>
|
||||
</div>
|
||||
<div class="hidden sm:flex items-center gap-1 text-slate-500 font-medium">
|
||||
<i class="fa-solid fa-shield-check text-emerald-600 text-xs"></i>
|
||||
<span>검증된 전문 선생님 100% 매칭</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- 3. 상단 히어로 배너 (H1 태그 포함) -->
|
||||
<!-- 3. 상단 히어로 배너 (H1 ➔ meta ➔ H2 ➔ P) -->
|
||||
<HeroBanner
|
||||
:region="parsed.region"
|
||||
:shortRegionName="parsed.shortRegionName"
|
||||
:grade="parsed.grade"
|
||||
:grade-short="parsed.gradeShort"
|
||||
:subjectName="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -63,24 +65,30 @@
|
||||
<!-- 9. 수업 진행 4단계 절차 안내 -->
|
||||
<ProcessGuide />
|
||||
|
||||
<!-- 10. 자주 묻는 질문 (FAQ) -->
|
||||
<!-- 10. 자주 묻는 질문 (FAQ - details/summary 시맨틱 구조) -->
|
||||
<FaqAccordion
|
||||
:regionDong="parsed.dong"
|
||||
:shortSido="parsed.shortSido"
|
||||
:grade="parsed.grade"
|
||||
:gradeShort="parsed.gradeShort"
|
||||
:subjectName="parsed.subjectName"
|
||||
/>
|
||||
|
||||
<!-- 11. 네이버 5개 멀티 이미지 매칭용 핵심 과외 프로그램 빠른 보기 -->
|
||||
<FastConsultFocus
|
||||
:regionDong="parsed.dong"
|
||||
:shortSido="parsed.shortSido"
|
||||
:grade="parsed.grade"
|
||||
:gradeShort="parsed.gradeShort"
|
||||
:subjectName="parsed.subjectName"
|
||||
/>
|
||||
|
||||
<!-- 12. 과목별 1타 강사진 갤러리 캐러셀 (클릭 시 페이지 모달 확대 및 상담 연동) -->
|
||||
<SubjectCarousel
|
||||
:regionDong="parsed.dong"
|
||||
:shortSido="parsed.shortSido"
|
||||
:grade="parsed.grade"
|
||||
:gradeShort="parsed.gradeShort"
|
||||
:currentSubject="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -97,13 +105,11 @@
|
||||
:defaultGrade="parsed.grade"
|
||||
:defaultSubject="parsed.subjectName"
|
||||
/>
|
||||
|
||||
<!-- 14. 클린 사이트 푸터 -->
|
||||
<AppFooter />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { parseRouteSlug, getCurriculumBySubject, getAllSubjectsList, getPopularRegions } from '~/utils/dataHelper'
|
||||
import { generateSeoMeta } from '~/utils/seoHelper'
|
||||
@@ -113,27 +119,26 @@ const config = useRuntimeConfig()
|
||||
const siteName = config.public?.siteName || '새솔 1:1 맞춤과외'
|
||||
|
||||
// URL 파라미터 파싱
|
||||
const slug = route.params.slug
|
||||
const parsed = parseRouteSlug(slug)
|
||||
const parsed = computed(() => parseRouteSlug(route.params.slug))
|
||||
|
||||
// 커리큘럼 데이터 로드
|
||||
const curriculum = getCurriculumBySubject(parsed.subjectKey)
|
||||
const curriculum = computed(() => getCurriculumBySubject(parsed.value.subjectKey))
|
||||
const allSubjects = getAllSubjectsList()
|
||||
const popularRegions = getPopularRegions(12)
|
||||
|
||||
// 네이버 Yeti 봇 100% 대응 SEO 메타태그 설정
|
||||
const seo = generateSeoMeta(
|
||||
parsed,
|
||||
const seo = computed(() => generateSeoMeta(
|
||||
parsed.value,
|
||||
config.public.siteName,
|
||||
config.public.siteDomain
|
||||
)
|
||||
))
|
||||
|
||||
useHead({
|
||||
title: seo.title,
|
||||
meta: seo.meta,
|
||||
link: seo.link,
|
||||
script: seo.script
|
||||
})
|
||||
useHead(() => ({
|
||||
title: seo.value.title,
|
||||
meta: seo.value.meta,
|
||||
link: seo.value.link,
|
||||
script: seo.value.script
|
||||
}))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<!-- 1. Header (클린 미니멀 프리미엄 네비게이션) -->
|
||||
<header class="bg-white/95 backdrop-blur-md border-b border-slate-200/80 sticky top-0 z-40 w-full transition-all">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6 py-3.5 flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<NuxtLink to="/" class="flex items-center gap-3">
|
||||
<div class="w-9 h-9 rounded-xl bg-blue-600 flex items-center justify-center text-white font-extrabold text-base shadow-sm">
|
||||
S
|
||||
{{ siteName.charAt(0) }}
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-extrabold text-lg sm:text-xl tracking-tight text-slate-900">{{ siteName }}</span>
|
||||
@@ -14,7 +14,7 @@
|
||||
교육청 등록 협력
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<a href="tel:010-5961-5807" class="hidden sm:flex items-center gap-1.5 text-sm font-semibold text-slate-600 hover:text-blue-600 transition">
|
||||
@@ -32,8 +32,8 @@
|
||||
<!-- 2. Main Body -->
|
||||
<main class="w-full pb-20">
|
||||
|
||||
<!-- 히어로 섹션 (AI 스타일 형광/물결 제거, 정제된 모던 에듀테크 캔버스) -->
|
||||
<section class="w-full bg-white border-b border-slate-200/80 pt-12 sm:pt-16 pb-20 px-4 sm:px-6 text-center relative overflow-hidden">
|
||||
<!-- 히어로 섹션 (네이버 상위 노출 DOM 순서: H1 ➔ meta ➔ H2 ➔ P) -->
|
||||
<section class="hero-section w-full bg-white border-b border-slate-200/80 pt-12 sm:pt-16 pb-20 px-4 sm:px-6 text-center relative overflow-hidden" itemscope itemtype="https://schema.org/EducationalOrganization">
|
||||
|
||||
<!-- 은은한 상단 엠비언트 라이트 (절제된 디자이너 톤) -->
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-blue-50/40 via-transparent to-transparent pointer-events-none"></div>
|
||||
@@ -46,16 +46,27 @@
|
||||
<span>경기 31개 시·군 전담 | 서울대·명문대 및 베테랑 전문 강사진 100% 신원 보증</span>
|
||||
</div>
|
||||
|
||||
<!-- 메인 H1 (검색 상위 노출 30자 규격 및 학부모 고의도 롱테일 키워드) -->
|
||||
<h1 class="text-3xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.2] sm:leading-[1.18] mb-4">
|
||||
경기 초·중·고 1:1 맞춤 과외 매칭<br class="hidden sm:inline" />
|
||||
<span class="text-blue-600">검증된 전문 선생님 100% 매칭</span>
|
||||
<!-- 1. H1 -->
|
||||
<h1 itemprop="headline" class="text-3xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.2] sm:leading-[1.18] mb-3">
|
||||
경기 중등 수학 과외 · 초·중·고 1:1 맞춤 과외 매칭<br class="hidden sm:inline" />
|
||||
<span class="text-blue-600">내신·수능 성적 향상의 시작</span>
|
||||
</h1>
|
||||
|
||||
<!-- 서브 헤드라인 (비용 시세 비교 + 무료 시범수업 신뢰 트리거) -->
|
||||
<p class="text-sm sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-8">
|
||||
과외 비용·시세 투명 비교부터 무료 시범수업 신청까지.<br class="hidden sm:inline" />
|
||||
경기 관내 학교별 기출 족보를 완벽 분석하여 <strong>내신 1등급 역전 솔루션</strong>을 제공합니다.
|
||||
<!-- 2. meta (마이크로데이터) -->
|
||||
<meta itemprop="name" :content="`${siteName} - 경기 중등 수학 과외 · 경기 중등 과외 1:1 매칭`" />
|
||||
<meta itemprop="description" content="경기 중등 수학 과외, 경기 중등 과외부터 초등·고등 국영수사과 1:1 방문·화상 맞춤 과외 매칭 및 과외비 투명 비교" />
|
||||
<meta itemprop="keywords" content="경기 중등 수학 과외, 경기 중등 과외, 경기 고등 수학 과외, 경기 고등 과외, 경기 초등 수학 과외, 경기 초등 과외, 경기 중등 영어 과외, 경기 과외, 정자동 과외, 수내동 과외" />
|
||||
<meta itemprop="image" :content="`${siteDomain}/img/math-tutoring.png`" />
|
||||
<link itemprop="url" :href="`${siteDomain}/`" />
|
||||
|
||||
<!-- 3. H2 -->
|
||||
<h2 class="hero-subtitle text-base sm:text-lg font-bold text-slate-700 mb-3">
|
||||
경기 중등 과외 · 초등·고등 국영수사과 검증된 전문 선생님 100% 1:1 매칭
|
||||
</h2>
|
||||
|
||||
<!-- 4. 일반글 P -->
|
||||
<p class="hero-desc text-sm sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-8">
|
||||
경기 중등 수학 과외 및 경기 중등 과외, 초등·고등 전 과목 과외 비용·시세 투명 비교부터 검증된 전문 선생님 무료 시범수업까지 학생에게 꼭 맞는 1:1 맞춤 수업을 제공합니다.
|
||||
</p>
|
||||
|
||||
<!-- 4대 핵심 신뢰 보증 지표 (Trust Bar) -->
|
||||
@@ -400,29 +411,31 @@
|
||||
</section>
|
||||
|
||||
<!-- 5. 과목별 1:1 맞춤과외 갤러리 캐러셀 (클릭 시 확대 모달 및 상담/이동) -->
|
||||
<SubjectCarousel grade="초·중·고" />
|
||||
<SubjectCarousel :regionDong="defaultDong" shortSido="경기" grade="중학생" gradeShort="중등" />
|
||||
|
||||
<!-- 6. FAQ 섹션 (정돈된 아코디언) -->
|
||||
<!-- 6. FAQ 섹션 (더세이브 방식 네이티브 details/summary 시맨틱 구조) -->
|
||||
<section class="mt-16 px-4 sm:px-6 max-w-4xl mx-auto">
|
||||
<header class="text-center mb-8">
|
||||
<span class="text-xs sm:text-sm font-bold text-slate-400 tracking-wider">FAQ</span>
|
||||
<h2 class="text-2xl sm:text-3xl font-extrabold text-slate-900 mt-1 tracking-tight">자주 묻는 질문</h2>
|
||||
<h2 class="text-2xl sm:text-3xl font-extrabold text-slate-900 mt-1 tracking-tight">경기 1:1 맞춤 과외 자주 묻는 질문</h2>
|
||||
<p class="text-xs sm:text-sm text-slate-500 mt-1">경기 학부모님들께서 가장 많이 문의하시는 과외 진행 절차입니다.</p>
|
||||
</header>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div v-for="(faq, idx) in faqs" :key="idx" class="border border-slate-200 rounded-xl overflow-hidden bg-white shadow-xs">
|
||||
<button @click="faq.open = !faq.open" class="w-full p-4 sm:p-5 text-left text-sm sm:text-base font-bold text-slate-800 flex justify-between items-center hover:bg-slate-50 transition">
|
||||
<details v-for="(faq, idx) in faqs" :key="idx" :open="idx === 0" class="qa border border-slate-200 rounded-xl overflow-hidden bg-white shadow-xs group">
|
||||
<summary class="w-full p-4 sm:p-5 text-left text-sm sm:text-base font-bold text-slate-800 cursor-pointer list-none flex justify-between items-center hover:bg-slate-50 transition">
|
||||
<span>{{ faq.q }}</span>
|
||||
<i class="fa-solid fa-chevron-down text-xs sm:text-sm text-slate-400 transition-transform" :class="{ 'rotate-180': faq.open }"></i>
|
||||
</button>
|
||||
<div v-show="faq.open" class="p-4 sm:p-5 pt-0 text-xs sm:text-sm text-slate-600 leading-relaxed border-t border-slate-100 bg-slate-50/50">
|
||||
<i class="fa-solid fa-chevron-down text-xs sm:text-sm text-slate-400 transition-transform group-open:rotate-180"></i>
|
||||
</summary>
|
||||
<div class="ans p-4 sm:p-5 pt-0 text-xs sm:text-sm text-slate-600 leading-relaxed border-t border-slate-100 bg-slate-50/50">
|
||||
{{ faq.a }}
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<InternalLinkHub :regionDong="defaultDong" grade="중학생" subjectName="수학" />
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
@@ -434,6 +447,7 @@ import { ref, reactive, computed, onMounted } from 'vue'
|
||||
const config = useRuntimeConfig()
|
||||
const siteName = config.public.siteName || '새솔 1:1 맞춤과외'
|
||||
const siteDomain = config.public.siteDomain || 'https://aeseo.shop'
|
||||
const defaultDong = '정자동'
|
||||
|
||||
const isSubmitting = ref(false)
|
||||
const submitSuccess = ref(false)
|
||||
@@ -500,7 +514,7 @@ onMounted(() => {
|
||||
}
|
||||
});
|
||||
}
|
||||
formData.grade = currentGradeOptions.value[1] || currentGradeOptions.value[0]
|
||||
formData.grade = currentGradeOptions.value[1] || currentGradeOptions.value[0]
|
||||
setInterval(() => {
|
||||
rollingIdx = (rollingIdx + 1) % rollingMessages.length
|
||||
currentNotice.value = rollingMessages[rollingIdx]
|
||||
@@ -548,24 +562,20 @@ function formatPhone(e) {
|
||||
|
||||
const faqs = reactive([
|
||||
{
|
||||
q: '무료 시범수업은 어떻게 진행되나요?',
|
||||
a: '신청서 접수 후 경기 전담 매니저가 유선으로 학생의 성향과 목표를 파악한 뒤, 가장 적합한 전문 선생님을 배정해 드립니다. 배정된 선생님이 1:1 방문 또는 화상으로 40~50분간 모의 수업 및 취약점 진단을 무료로 진행하며, 수업 후 계속 진행 여부를 편안하게 결정하실 수 있습니다.',
|
||||
open: true
|
||||
q: '경기 중등 수학 과외 및 경기 중등 과외 무료 시범수업은 어떻게 진행되나요?',
|
||||
a: '신청서 접수 후 경기 전담 매니저가 유선으로 학생의 성향과 목표를 파악한 뒤, 경기 초·중·고 과외 전문 선생님을 배정해 드립니다. 배정된 선생님이 1:1 방문 또는 화상으로 40~50분간 모의 수업 및 취약점 진단을 무료로 진행하며, 수업 후 계속 진행 여부를 편안하게 결정하실 수 있습니다.'
|
||||
},
|
||||
{
|
||||
q: '과외 비용 및 시세는 어떻게 되나요?',
|
||||
a: '학년(초등/중등/고등)과 주당 수업 횟수(주 1회, 주 2회 등), 수업 시간(회당 60분~120분)에 따라 교육청 가이드라인에 맞춘 투명한 표준 시세로 책정됩니다. 상담 시 거품 없는 정확한 우리 동네 과외 비용을 안내해 드립니다.',
|
||||
open: false
|
||||
q: '경기 중등 수학 과외 · 경기 초·중·고 과외 비용 및 시세는 어떻게 되나요?',
|
||||
a: '경기 중등 과외 및 초등·고등 과외 비용은 학년과 주당 수업 횟수(주 1회, 주 2회 등), 수업 시간(회당 60분~120분)에 따라 교육청 가이드라인에 맞춘 투명한 표준 시세로 책정됩니다. 상담 시 거품 없는 정확한 우리 동네 과외 비용을 안내해 드립니다.'
|
||||
},
|
||||
{
|
||||
q: '선생님 신원과 학력 검증은 어떻게 이루어지나요?',
|
||||
a: '모든 강사진은 주민등록초본, 대학/대학원 재학 및 졸업증명서, 성범죄 경력 조회 등 엄격한 4단계 서류 검증과 교육청 개인과외교습자 신고를 100% 완료한 검증된 전문 선생님입니다.',
|
||||
open: false
|
||||
q: '경기 중등 과외 선생님 신원과 학력 검증은 어떻게 이루어지나요?',
|
||||
a: '경기 중등 수학 과외 및 경기 초·중·고 과외 모든 강사진은 주민등록초본, 대학/대학원 재학 및 졸업증명서, 성범죄 경력 조회 등 엄격한 4단계 서류 검증과 교육청 개인과외교습자 신고를 100% 완료한 검증된 전문 선생님입니다.'
|
||||
},
|
||||
{
|
||||
q: '선생님이 아이와 맞지 않으면 어떻게 하나요?',
|
||||
a: '무료 시범수업을 통해 사전에 호흡을 맞출 수 있으며, 정규 수업 진행 중에도 선생님 교체를 희망하시면 추가 비용 없이 100% 만족하실 때까지 새로운 선생님으로 무료 재매칭을 진행해 드립니다.',
|
||||
open: false
|
||||
q: '경기 중등 수학 과외 선생님이 아이와 맞지 않으면 교체가 가능한가요?',
|
||||
a: '네, 경기 중등 과외 무료 시범수업을 통해 사전에 호흡을 맞출 수 있으며, 정규 수업 진행 중에도 선생님 교체를 희망하시면 추가 비용 없이 100% 만족하실 때까지 새로운 선생님으로 무료 재매칭을 진행해 드립니다.'
|
||||
}
|
||||
])
|
||||
|
||||
@@ -605,49 +615,97 @@ async function handleSubmit() {
|
||||
}
|
||||
}
|
||||
|
||||
// SEO 태그 설정 (사용자 가이드 30~35자 내외 글자 수 및 고의도 롱테일 키워드 100% 준수)
|
||||
// SEO 태그 및 소셜 메타데이터 (네이버/구글 검색 최적화 및 3종 구조화 데이터 JSON-LD)
|
||||
const homeCanonical = siteDomain.endsWith('/') ? siteDomain : `${siteDomain}/`
|
||||
const homeTitle = `경기 중등 수학 과외 · 경기 중등 과외 | 초·중·고 1:1 맞춤 과외 ${siteName}`
|
||||
const homeDesc = `경기 중등 수학 과외, 경기 중등 과외, ${defaultDong} 중등 수학 과외 전문 ${siteName}! 초·중·고 국영수사과 과외 비용·시세 투명 비교부터 검증된 전문 선생님 무료 시범수업 신청까지 1:1 맞춤 솔루션`
|
||||
const allBrandImages = [
|
||||
`${siteDomain}/img/og-main.png`,
|
||||
`${siteDomain}/img/math-tutoring.png`,
|
||||
`${siteDomain}/img/english-tutoring.png`,
|
||||
`${siteDomain}/img/korean-tutoring.png`,
|
||||
`${siteDomain}/img/science-tutoring.png`,
|
||||
`${siteDomain}/img/social-studies-tutoring.png`
|
||||
]
|
||||
|
||||
// SEO 태그 및 소셜 메타데이터 (더세이브 방식 메타태그 + 3분할 구조화 데이터 JSON-LD)
|
||||
useHead({
|
||||
title: '로열클래스 1:1 과외 | 경기 초·중·고 검증된 맞춤 과외 매칭',
|
||||
title: homeTitle,
|
||||
link: [
|
||||
{ rel: 'canonical', href: 'https://aeseo.shop/' }
|
||||
{ rel: 'canonical', href: homeCanonical }
|
||||
],
|
||||
meta: [
|
||||
{ name: 'robots', content: 'index,follow' },
|
||||
{ name: 'naver-site-verification', content: 'bfbfcb6ed8c107d05503feed914769a29b07cf06' },
|
||||
{ name: 'description', content: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 명문대 및 베테랑 전문 강사진 1:1 맞춤 배정 솔루션' },
|
||||
{ name: 'description', content: homeDesc },
|
||||
{ name: 'keywords', content: '경기 중등 수학 과외, 경기 중등 과외, 경기 고등 수학 과외, 경기 고등 과외, 경기 초등 수학 과외, 경기 초등 과외, 경기 중등 영어 과외, 경기 고등 영어 과외, 경기 과외, 정자동 과외, 수내동 과외, 정자동 중등 수학 과외' },
|
||||
{ property: 'og:type', content: 'website' },
|
||||
{ property: 'og:site_name', content: '로열클래스 1:1 과외' },
|
||||
{ property: 'og:title', content: '로열클래스 1:1 과외 | 경기 초·중·고 맞춤 과외 매칭' },
|
||||
{ property: 'og:description', content: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 검증된 전문 선생님 100% 매칭' },
|
||||
{ property: 'og:url', content: 'https://aeseo.shop/' },
|
||||
{ property: 'og:image', content: 'https://aeseo.shop/img/og-main.png' },
|
||||
{ property: 'og:locale', content: 'ko_KR' },
|
||||
{ property: 'og:site_name', content: siteName },
|
||||
{ property: 'og:title', content: homeTitle },
|
||||
{ property: 'og:description', content: homeDesc },
|
||||
{ property: 'og:url', content: homeCanonical },
|
||||
{ property: 'og:image', content: `${siteDomain}/img/og-main.png` },
|
||||
{ property: 'og:image:type', content: 'image/png' },
|
||||
{ property: 'og:image:width', content: '1200' },
|
||||
{ property: 'og:image:height', content: '630' },
|
||||
{ property: 'og:image:alt', content: '경기 중등 수학 과외 · 경기 중등 과외' },
|
||||
{ name: 'twitter:card', content: 'summary_large_image' },
|
||||
{ name: 'twitter:title', content: '로열클래스 1:1 과외 | 경기 초·중·고 맞춤 과외 매칭' },
|
||||
{ name: 'twitter:description', content: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 검증된 전문 선생님 100% 매칭' },
|
||||
{ name: 'twitter:image', content: 'https://aeseo.shop/img/og-main.png' }
|
||||
{ name: 'twitter:title', content: homeTitle },
|
||||
{ name: 'twitter:description', content: homeDesc },
|
||||
{ name: 'twitter:image', content: `${siteDomain}/img/og-main.png` }
|
||||
],
|
||||
script: [
|
||||
// 1. EducationalOrganization / LocalBusiness 스키마
|
||||
// 1. @graph (WebSite + WebPage + ImageObject + EducationalOrganization + LocalBusiness)
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': ['EducationalOrganization', 'LocalBusiness'],
|
||||
name: '로열클래스 1:1 과외',
|
||||
telephone: '+82-10-5961-5807',
|
||||
url: 'https://aeseo.shop/',
|
||||
image: 'https://aeseo.shop/img/og-main.png',
|
||||
address: {
|
||||
'@type': 'PostalAddress',
|
||||
streetAddress: '판교역로 146 알파리움 3층',
|
||||
addressLocality: '분당구',
|
||||
addressRegion: '경기도',
|
||||
addressCountry: 'KR'
|
||||
},
|
||||
description: '경기 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관',
|
||||
areaServed: '경기도 전지역'
|
||||
'@graph': [
|
||||
{
|
||||
'@type': 'WebSite',
|
||||
'@id': `${siteDomain}/#site`,
|
||||
url: homeCanonical,
|
||||
name: siteName,
|
||||
inLanguage: 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'WebPage',
|
||||
'@id': `${homeCanonical}#page`,
|
||||
url: homeCanonical,
|
||||
name: homeTitle,
|
||||
description: homeDesc,
|
||||
isPartOf: { '@id': `${siteDomain}/#site` },
|
||||
primaryImageOfPage: { '@id': `${homeCanonical}#img` },
|
||||
inLanguage: 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'ImageObject',
|
||||
'@id': `${homeCanonical}#img`,
|
||||
url: `${siteDomain}/img/math-tutoring.png`,
|
||||
contentUrl: `${siteDomain}/img/math-tutoring.png`,
|
||||
width: 1080,
|
||||
height: 1080,
|
||||
caption: '경기 중등 수학 과외 · 경기 중등 과외'
|
||||
},
|
||||
{
|
||||
'@type': ['EducationalOrganization', 'LocalBusiness'],
|
||||
'@id': `${siteDomain}/#org`,
|
||||
name: siteName,
|
||||
telephone: '+82-10-5961-5807',
|
||||
url: homeCanonical,
|
||||
image: allBrandImages,
|
||||
priceRange: '₩₩',
|
||||
address: {
|
||||
'@type': 'PostalAddress',
|
||||
streetAddress: '판교역로 146 알파리움 3층',
|
||||
addressLocality: '분당구',
|
||||
addressRegion: '경기도',
|
||||
addressCountry: 'KR'
|
||||
},
|
||||
description: homeDesc,
|
||||
areaServed: '경기도 전지역'
|
||||
}
|
||||
]
|
||||
})
|
||||
},
|
||||
// 2. FAQPage 스키마
|
||||
@@ -666,50 +724,57 @@ useHead({
|
||||
}))
|
||||
})
|
||||
},
|
||||
// 3. ItemList 과목별 갤러리 섹션 스키마
|
||||
// 3. ItemList 과목별 및 학년별 서브 라우터 캐러셀 스키마 (최상위 name, url, image + item: Course 바인딩)
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'ItemList',
|
||||
name: '과목별 1:1 맞춤 과외 프로그램',
|
||||
name: '경기 중등 수학 과외 · 경기 중등 과외 및 학년별·과목별 1:1 맞춤 과외 프로그램',
|
||||
itemListElement: [
|
||||
{
|
||||
{ sub: '수학', grade: '중학생', title: '경기 중등 수학 과외 · 중학생 수학과외', desc: '경기 중등 수학 과외 및 경기 중등 과외 개념 구멍 추적 및 킬러 문항 1:1 완파', img: 'math-tutoring.png' },
|
||||
{ sub: '영어', grade: '중학생', title: '경기 중등 영어 과외 · 중학생 영어과외', desc: '경기 중등 영어 과외 및 경기 중등 과외 교과서·부교재 전 지문 변형 및 서술형 영작', img: 'english-tutoring.png' },
|
||||
{ sub: '국어', grade: '중학생', title: '경기 중등 국어 과외 · 중학생 국어과외', desc: '경기 중등 국어 과외 및 비문학 독해 논리와 교과서 문학 1:1 정밀 분석', img: 'korean-tutoring.png' },
|
||||
{ sub: '과학', grade: '중학생', title: '경기 중등 과학 과외 · 중학생 과학과외', desc: '경기 중등 과학 과외 및 통합과학 원리 이해·물화생지 킬러 단원 정복', img: 'science-tutoring.png' },
|
||||
{ sub: '사회', grade: '중학생', title: '경기 중등 사회 과외 · 중학생 사회과외', desc: '경기 중등 사회 과외 및 통합사회·한국사 핵심 흐름 만점 전략', img: 'social-studies-tutoring.png' },
|
||||
{ sub: '수학', grade: '초등학생', title: '경기 초등 수학 과외 · 초등학생 수학과외', desc: '경기 초등 수학 과외 기초 연산 습관 형성 및 중등 선행 심화 대비', img: 'math-tutoring.png' },
|
||||
{ sub: '영어', grade: '고등학생', title: '경기 고등 영어 과외 · 고등학생 영어과외', desc: '경기 고등 영어 과외 내신 서술형 감점 방지 및 수능 1등급 완성', img: 'english-tutoring.png' },
|
||||
{ sub: '수학', grade: '고등학생', title: '경기 고등 수학 과외 · 고등학생 수학과외', desc: '경기 고등 수학 과외 공통수학·미적분 킬러 문항 및 내신 1등급 전략', img: 'math-tutoring.png' }
|
||||
].map((item, idx) => {
|
||||
const courseUrl = `${siteDomain}/${encodeURIComponent(defaultDong)}/${encodeURIComponent(item.grade)}/${encodeURIComponent(item.sub)}`
|
||||
const courseImg = `${siteDomain}/img/${item.img}`
|
||||
const courseName = `${item.title} (${defaultDong})`
|
||||
return {
|
||||
'@type': 'ListItem',
|
||||
position: 1,
|
||||
name: '수학과외',
|
||||
description: '개념 구멍 추적 및 킬러 문항 1:1 완파',
|
||||
image: 'https://aeseo.shop/img/math-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 2,
|
||||
name: '영어과외',
|
||||
description: '교과서·부교재 전 지문 변형 및 서술형 영작',
|
||||
image: 'https://aeseo.shop/img/english-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 3,
|
||||
name: '국어과외',
|
||||
description: '비문학 독해 논리와 교과서 문학 1:1 정밀 분석',
|
||||
image: 'https://aeseo.shop/img/korean-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 4,
|
||||
name: '과학과외',
|
||||
description: '통합과학 원리 이해 및 물화생지 킬러 단원 정복',
|
||||
image: 'https://aeseo.shop/img/science-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 5,
|
||||
name: '사회과외',
|
||||
description: '통합사회·한국사 핵심 흐름 및 사탐 만점 전략',
|
||||
image: 'https://aeseo.shop/img/social-studies-tutoring.png'
|
||||
position: idx + 1,
|
||||
name: courseName,
|
||||
url: courseUrl,
|
||||
image: courseImg,
|
||||
item: {
|
||||
'@type': 'Course',
|
||||
name: courseName,
|
||||
description: item.desc,
|
||||
url: courseUrl,
|
||||
image: courseImg,
|
||||
provider: {
|
||||
'@type': 'Organization',
|
||||
name: siteName,
|
||||
sameAs: siteDomain
|
||||
},
|
||||
offers: {
|
||||
'@type': 'Offer',
|
||||
category: 'Paid',
|
||||
priceCurrency: 'KRW',
|
||||
availability: 'https://schema.org/InStock',
|
||||
url: courseUrl
|
||||
},
|
||||
hasCourseInstance: {
|
||||
'@type': 'CourseInstance',
|
||||
courseMode: ['onsite', 'online']
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
</defs>
|
||||
<rect width="1200" height="630" fill="url(#bg)"/>
|
||||
<rect x="80" y="80" width="160" height="48" rx="8" fill="#fbbf24"/>
|
||||
<text x="160" y="112" font-family="'Pretendard', sans-serif" font-size="22" font-weight="900" fill="#1e293b" text-anchor="middle">AESEO</text>
|
||||
<text x="160" y="112" font-family="'Pretendard', sans-serif" font-size="22" font-weight="900" fill="#1e293b" text-anchor="middle">새솔 맞춤과외</text>
|
||||
<text x="80" y="240" font-family="'Pretendard', sans-serif" font-size="56" font-weight="900" fill="#ffffff">우리 동네 초·중·고 1:1 맞춤 과외</text>
|
||||
<text x="80" y="320" font-family="'Pretendard', sans-serif" font-size="68" font-weight="900" fill="#fbbf24">내신 1등급 전문 과외애서</text>
|
||||
<text x="80" y="320" font-family="'Pretendard', sans-serif" font-size="68" font-weight="900" fill="#fbbf24">내신 1등급 전문 새솔 맞춤과외</text>
|
||||
<text x="80" y="420" font-family="'Pretendard', sans-serif" font-size="30" font-weight="500" fill="#e0e7ff">국어 · 영어 · 수학 · 과학 · 사회 · 수행평가 세특</text>
|
||||
<text x="80" y="480" font-family="'Pretendard', sans-serif" font-size="28" font-weight="700" fill="#ffffff">전국 568개 동 학교별 기출 족보 완벽 분석</text>
|
||||
<rect x="80" y="530" width="340" height="50" rx="25" fill="#10b981"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -83,7 +83,7 @@
|
||||
|
||||
<!-- 성적 상승 그래프 비주얼 -->
|
||||
<text x="35" y="55" fill="#f8fafc" font-size="18" font-weight="800" font-family="'Pretendard', sans-serif">
|
||||
AESEO 성적 향상 지표
|
||||
새솔 맞춤과외 성적 향상 지표
|
||||
</text>
|
||||
<text x="35" y="80" fill="#94a3b8" font-size="13" font-family="'Pretendard', sans-serif">
|
||||
수강생 평균 2.3등급 수직 상승
|
||||
@@ -96,7 +96,7 @@
|
||||
<text x="32" y="55" fill="#94a3b8" font-size="13" font-weight="700" text-anchor="middle">4등급</text>
|
||||
<text x="32" y="185" fill="#94a3b8" font-size="12" text-anchor="middle">수강 전</text>
|
||||
|
||||
<!-- 과외애서 수강 후 바 -->
|
||||
<!-- 새솔 맞춤과외 수강 후 바 -->
|
||||
<rect x="95" y="10" width="75" height="150" rx="6" fill="url(#goldGrad)" />
|
||||
<text x="132" y="-5" fill="#f59e0b" font-size="16" font-weight="900" text-anchor="middle">1등급!</text>
|
||||
<text x="132" y="185" fill="#ffffff" font-size="13" font-weight="800" text-anchor="middle">수강 3개월</text>
|
||||
@@ -118,7 +118,7 @@
|
||||
|
||||
<!-- 우측 하단 워터마크 -->
|
||||
<text x="355" y="325" fill="#ffffff" opacity="0.3" font-size="13" font-weight="800" text-anchor="end" font-family="'Pretendard', sans-serif">
|
||||
AESEO TUTORING POSTER
|
||||
새솔 맞춤과외 TUTORING POSTER
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 4.9 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 4.9 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.0 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.0 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.0 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.0 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.0 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 4.9 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.0 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.0 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 4.9 MiB |
@@ -1,33 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title><![CDATA[로열클래스 1:1 과외]]></title>
|
||||
<title><![CDATA[새솔 1:1 맞춤과외]]></title>
|
||||
<link>https://aeseo.shop/</link>
|
||||
<description><![CDATA[경기 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관]]></description>
|
||||
<language>ko</language>
|
||||
<pubDate>Tue, 20 Oct 2026 03:35:57 GMT</pubDate>
|
||||
<lastBuildDate>Tue, 20 Oct 2026 03:35:57 GMT</lastBuildDate>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<lastBuildDate>Wed, 04 Nov 2026 00:47:43 GMT</lastBuildDate>
|
||||
<atom:link href="https://aeseo.shop/rss.xml" rel="self" type="application/rss+xml"/>
|
||||
<item>
|
||||
<title><![CDATA[경기 초·중·고 1:1 맞춤 과외 매칭]]></title>
|
||||
<link>https://aeseo.shop/</link>
|
||||
<description><![CDATA[과외 비용·시세 투명 비교부터 무료 시범수업 신청까지]]></description>
|
||||
<pubDate>Tue, 20 Oct 2026 03:35:57 GMT</pubDate>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<guid>https://aeseo.shop/</guid>
|
||||
</item>
|
||||
<item>
|
||||
<title><![CDATA[분당동 중학생 수학과외 1:1 맞춤 수업]]></title>
|
||||
<link>https://aeseo.shop/%EB%B6%84%EB%8B%B9%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</link>
|
||||
<description><![CDATA[분당 인근 학교별 내신 기출 분석]]></description>
|
||||
<pubDate>Tue, 20 Oct 2026 03:35:57 GMT</pubDate>
|
||||
<guid>https://aeseo.shop/%EB%B6%84%EB%8B%B9%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</guid>
|
||||
<title><![CDATA[수내동 중학생 수학과외 1:1 맞춤 수업]]></title>
|
||||
<link>https://aeseo.shop/%EC%88%98%EB%82%B4%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</link>
|
||||
<description><![CDATA[분당 수내동 인근 학교별 내신 기출 분석]]></description>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<guid>https://aeseo.shop/%EC%88%98%EB%82%B4%EB%8F%99/%EC%A4%91%ED%95%99%EC%83%9D/%EC%88%98%ED%95%99</guid>
|
||||
</item>
|
||||
<item>
|
||||
<title><![CDATA[일산동 고등학생 영어과외 1:1 맞춤 수업]]></title>
|
||||
<link>https://aeseo.shop/%EC%9D%BC%EC%82%B0%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</link>
|
||||
<title><![CDATA[마두동 고등학생 영어과외 1:1 맞춤 수업]]></title>
|
||||
<link>https://aeseo.shop/%EB%A7%88%EB%91%90%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</link>
|
||||
<description><![CDATA[일산 학군 내신 서술형 대비]]></description>
|
||||
<pubDate>Tue, 20 Oct 2026 03:35:57 GMT</pubDate>
|
||||
<guid>https://aeseo.shop/%EC%9D%BC%EC%82%B0%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</guid>
|
||||
<pubDate>Wed, 04 Nov 2026 00:47:43 GMT</pubDate>
|
||||
<guid>https://aeseo.shop/%EB%A7%88%EB%91%90%EB%8F%99/%EA%B3%A0%EB%93%B1%ED%95%99%EC%83%9D/%EC%98%81%EC%96%B4</guid>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
|
||||
@@ -29,7 +29,7 @@ export default defineEventHandler(async (event) => {
|
||||
}
|
||||
|
||||
const webhookUrl = config.discordWebhookUrl || 'https://discordapp.com/api/webhooks/1557204310369116210/9J4y96kmSbYNGtw5OxRgIz7InWcM8o3f8UX0Ad71-IyofwdS7tWmXkF7dj457-I8Ypiu'
|
||||
const siteName = config.public.siteName || '1:1 맞춤과외'
|
||||
const siteName = config.public.siteName || '새솔 1:1 맞춤과외'
|
||||
const siteDomain = config.public.siteDomain || 'https://aeseo.shop'
|
||||
|
||||
// 한국 시간 (KST)
|
||||
|
||||
@@ -4,24 +4,56 @@ export default defineEventHandler((event) => {
|
||||
const config = useRuntimeConfig()
|
||||
const baseUrl = config.public.siteDomain || 'https://aeseo.shop'
|
||||
const list = regionsData.list as Array<{ sido: string, sigungu: string, dong: string }>
|
||||
const today = new Date().toISOString().split('T')[0]
|
||||
|
||||
const subjects = ['영어', '수학', '국어', '통합과학', '통합사회']
|
||||
const grades = ['중학생', '고등학생']
|
||||
const subjectImages: Record<string, string> = {
|
||||
'수학': `${baseUrl}/img/math-tutoring.png`,
|
||||
'영어': `${baseUrl}/img/english-tutoring.png`,
|
||||
'국어': `${baseUrl}/img/korean-tutoring.png`,
|
||||
'과학': `${baseUrl}/img/science-tutoring.png`,
|
||||
'사회': `${baseUrl}/img/social-studies-tutoring.png`
|
||||
}
|
||||
const subjects = ['수학', '영어', '국어', '과학', '사회']
|
||||
const grades = ['초등학생', '중학생', '고등학생']
|
||||
|
||||
let xml = `<?xml version="1.0" encoding="UTF-8"?>\n`
|
||||
xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n`
|
||||
xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">\n`
|
||||
|
||||
// 메인
|
||||
xml += ` <url>\n <loc>${baseUrl}/</loc>\n <changefreq>daily</changefreq>\n <priority>1.0</priority>\n </url>\n`
|
||||
// 메인 (대표 이미지 + 5대 과목 이미지 모두 포함)
|
||||
xml += ` <url>\n`
|
||||
xml += ` <loc>${baseUrl}/</loc>\n`
|
||||
xml += ` <lastmod>${today}</lastmod>\n`
|
||||
xml += ` <changefreq>daily</changefreq>\n`
|
||||
xml += ` <priority>1.0</priority>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/og-main.png</image:loc></image:image>\n`
|
||||
subjects.forEach(sub => {
|
||||
xml += ` <image:image><image:loc>${subjectImages[sub]}</image:loc></image:image>\n`
|
||||
})
|
||||
xml += ` </url>\n`
|
||||
|
||||
// 568개 동별 주요 과목 및 학년 URL 생성
|
||||
// 동별 주요 과목 및 학년 URL 생성
|
||||
list.forEach(r => {
|
||||
// 1. 동 대표
|
||||
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(r.dong)}</loc>\n <changefreq>weekly</changefreq>\n <priority>0.8</priority>\n </url>\n`
|
||||
xml += ` <url>\n`
|
||||
xml += ` <loc>${baseUrl}/${encodeURIComponent(r.dong)}</loc>\n`
|
||||
xml += ` <lastmod>${today}</lastmod>\n`
|
||||
xml += ` <changefreq>weekly</changefreq>\n`
|
||||
xml += ` <priority>0.8</priority>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/og-main.png</image:loc></image:image>\n`
|
||||
xml += ` <image:image><image:loc>${baseUrl}/img/math-tutoring.png</image:loc></image:image>\n`
|
||||
xml += ` </url>\n`
|
||||
|
||||
// 2. 동-과목-학년 대표 조합
|
||||
subjects.slice(0, 3).forEach(sub => {
|
||||
xml += ` <url>\n <loc>${baseUrl}/${encodeURIComponent(r.dong)}-${encodeURIComponent(grades[0])}-${encodeURIComponent(sub)}</loc>\n <changefreq>weekly</changefreq>\n <priority>0.7</priority>\n </url>\n`
|
||||
// 2. 동/학년/과목 대표 조합
|
||||
grades.forEach(g => {
|
||||
subjects.forEach(sub => {
|
||||
xml += ` <url>\n`
|
||||
xml += ` <loc>${baseUrl}/${encodeURIComponent(r.dong)}/${encodeURIComponent(g)}/${encodeURIComponent(sub)}</loc>\n`
|
||||
xml += ` <lastmod>${today}</lastmod>\n`
|
||||
xml += ` <changefreq>weekly</changefreq>\n`
|
||||
xml += ` <priority>0.7</priority>\n`
|
||||
xml += ` <image:image><image:loc>${subjectImages[sub]}</image:loc></image:image>\n`
|
||||
xml += ` </url>\n`
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -17,10 +17,12 @@ export interface ParsedRouteParams {
|
||||
dong: string
|
||||
shortRegionName: string
|
||||
grade: string
|
||||
gradeShort: string
|
||||
subjectKey: string
|
||||
subjectName: string
|
||||
targetTerm: string
|
||||
fullKeyword: string
|
||||
isRegionOnly?: boolean
|
||||
}
|
||||
|
||||
// 5대 핵심 과목 정의
|
||||
@@ -34,29 +36,33 @@ export const SUBJECTS_MAP: Record<string, { key: string, name: string, badge: st
|
||||
|
||||
// 학년 정의
|
||||
export const GRADES_LIST = [
|
||||
{ key: 'middle', name: '중학생', aliases: ['중학생', '중1', '중2', '중3', '중등'] },
|
||||
{ key: 'high', name: '고등학생', aliases: ['고등학생', '고1', '고2', '고3', '고등', '예비고1'] },
|
||||
{ key: 'elem', name: '초등학생', aliases: ['초등학생', '초등', '초5', '초6'] }
|
||||
{ key: 'middle', name: '중학생', shortName: '중등', aliases: ['중학생', '중1', '중2', '중3', '중등'] },
|
||||
{ key: 'high', name: '고등학생', shortName: '고등', aliases: ['고등학생', '고1', '고2', '고3', '고등', '예비고1', 'N수', '재수'] },
|
||||
{ key: 'elem', name: '초등학생', shortName: '초등', aliases: ['초등학생', '초등', '초1', '초2', '초3', '초4', '초5', '초6'] }
|
||||
]
|
||||
|
||||
// 동 이름으로 지역 검색
|
||||
export function getRegionByDong(dongQuery: string): RegionInfo | null {
|
||||
if (!dongQuery) return null
|
||||
const clean = dongQuery.trim().replace(/동$/, '') // '황금' 또는 '황금동' 모두 매칭
|
||||
const clean = dongQuery.trim().replace(/[동읍면리가]$/, '')
|
||||
const map = regionsData.dongMap as Record<string, RegionInfo[]>
|
||||
|
||||
// 1. 정확 매칭 (황금동)
|
||||
// 1. 정확 매칭
|
||||
if (map[dongQuery] && map[dongQuery].length > 0) {
|
||||
return map[dongQuery][0]
|
||||
}
|
||||
// 2. '동' 붙여서 매칭
|
||||
if (map[dongQuery + '동'] && map[dongQuery + '동'].length > 0) {
|
||||
return map[dongQuery + '동'][0]
|
||||
// 2. '동', '읍', '면' 붙여서 매칭
|
||||
for (const suffix of ['동', '읍', '면']) {
|
||||
if (map[clean + suffix] && map[clean + suffix].length > 0) {
|
||||
return map[clean + suffix][0]
|
||||
}
|
||||
}
|
||||
// 3. 리스트 전체 순회 매칭
|
||||
const found = (regionsData.list as RegionInfo[]).find(r =>
|
||||
r.dong === dongQuery ||
|
||||
r.dong === (dongQuery + '동') ||
|
||||
r.dong === (clean + '동') ||
|
||||
r.dong === (clean + '읍') ||
|
||||
r.dong === (clean + '면') ||
|
||||
r.dong.startsWith(clean)
|
||||
)
|
||||
return found || null
|
||||
@@ -99,12 +105,6 @@ export function getShortRegionName(sido: string, dong: string, sigungu?: string)
|
||||
}
|
||||
|
||||
// 지능형 URL 슬러그 파서
|
||||
// 지원 예시:
|
||||
// - ['대구광역시', '수성구', '황금동']
|
||||
// - ['대구광역시', '황금동', '중학생', '영어']
|
||||
// - ['황금동', '중학생', '영어']
|
||||
// - ['황금동-중학생-영어']
|
||||
// - '대구광역시-황금동-중학생-영어'
|
||||
export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams {
|
||||
let tokens: string[] = []
|
||||
|
||||
@@ -117,6 +117,7 @@ export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams
|
||||
|
||||
let matchedRegion: RegionInfo | null = null
|
||||
let detectedGrade = '중학생'
|
||||
let detectedGradeShort = '중등'
|
||||
let detectedSubjectKey = 'english'
|
||||
let detectedSubjectName = '영어'
|
||||
let detectedTerm = '과외'
|
||||
@@ -141,30 +142,38 @@ export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams
|
||||
}
|
||||
}
|
||||
|
||||
// 기본값 (568개 타겟 지역 중 첫 번째 기준)
|
||||
// 기본값 (타겟 지역 중 첫 번째 기준)
|
||||
if (!matchedRegion) {
|
||||
matchedRegion = (regionsData.list as RegionInfo[])[0] || {
|
||||
fullName: '경기도 고양시 덕양구 고양동',
|
||||
fullName: '경기도 성남시 분당구 수내동',
|
||||
sido: '경기도',
|
||||
sigungu: '고양시 덕양구',
|
||||
dong: '고양동'
|
||||
sigungu: '성남시 분당구',
|
||||
dong: '수내동'
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 학년 추출
|
||||
let hasExplicitGrade = false
|
||||
const fullText = tokens.join(' ')
|
||||
for (const g of GRADES_LIST) {
|
||||
if (g.aliases.some(a => fullText.includes(a))) {
|
||||
detectedGrade = g.name
|
||||
detectedGradeShort = g.shortName
|
||||
hasExplicitGrade = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!detectedGradeShort) {
|
||||
detectedGradeShort = detectedGrade === '초등학생' ? '초등' : detectedGrade === '고등학생' ? '고등' : '중등'
|
||||
}
|
||||
|
||||
// 4. 과목 추출
|
||||
let hasExplicitSubject = false
|
||||
for (const [key, sub] of Object.entries(SUBJECTS_MAP)) {
|
||||
if (sub.aliases.some(a => fullText.includes(a))) {
|
||||
detectedSubjectKey = key
|
||||
detectedSubjectName = sub.name
|
||||
hasExplicitSubject = true
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -188,10 +197,12 @@ export function parseRouteSlug(slugInput: string | string[]): ParsedRouteParams
|
||||
dong: matchedRegion.dong,
|
||||
shortRegionName,
|
||||
grade: detectedGrade,
|
||||
gradeShort: detectedGradeShort,
|
||||
subjectKey: detectedSubjectKey,
|
||||
subjectName: detectedSubjectName,
|
||||
targetTerm: detectedTerm,
|
||||
fullKeyword
|
||||
fullKeyword,
|
||||
isRegionOnly: !hasExplicitGrade && !hasExplicitSubject
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,150 +1,315 @@
|
||||
import type { ParsedRouteParams } from './dataHelper'
|
||||
import type { ParsedRouteParams } from './dataHelper'
|
||||
import { getShortRegionName } from './dataHelper'
|
||||
|
||||
const SUBJECT_IMAGE_MAP: Record<string, string> = {
|
||||
math: '/img/math-tutoring.png',
|
||||
english: '/img/english-tutoring.png',
|
||||
korean: '/img/korean-tutoring.png',
|
||||
science: '/img/science-tutoring.png',
|
||||
social: '/img/social-studies-tutoring.png'
|
||||
}
|
||||
|
||||
const SUBJECT_LIST = [
|
||||
{ key: 'math', name: '수학', desc: '개념 구멍 추적 및 킬러 문항 1:1 완파', img: '/img/math-tutoring.png' },
|
||||
{ key: 'english', name: '영어', desc: '교과서·부교재 전 지문 변형 및 서술형 영작', img: '/img/english-tutoring.png' },
|
||||
{ key: 'korean', name: '국어', desc: '비문학 독해 논리와 교과서 문학 1:1 정밀 분석', img: '/img/korean-tutoring.png' },
|
||||
{ key: 'science', name: '과학', desc: '통합과학 원리 이해 및 물화생지 킬러 단원 정복', img: '/img/science-tutoring.png' },
|
||||
{ key: 'social', name: '사회', desc: '통합사회·한국사 핵심 흐름 및 사탐 만점 전략', img: '/img/social-studies-tutoring.png' }
|
||||
]
|
||||
|
||||
const GRADE_LIST = ['초등학생', '중학생', '고등학생']
|
||||
|
||||
export function generateSeoMeta(parsed: ParsedRouteParams, siteName = '새솔 1:1 맞춤과외', siteDomain = 'https://aeseo.shop') {
|
||||
const { sido, sigungu, dong, shortRegionName, grade, subjectName, targetTerm, fullKeyword } = parsed
|
||||
const { sido, sigungu, dong, shortRegionName, grade, subjectKey, subjectName, isRegionOnly } = parsed
|
||||
|
||||
const shortSido = (sido || '').replace(/특별시|광역시|특별자치시|도/g, '').trim() || '경기'
|
||||
const gradeShort = parsed.gradeShort || (grade === '초등학생' ? '초등' : grade === '고등학생' ? '고등' : '중등')
|
||||
const regionTitle = shortRegionName || getShortRegionName(sido, dong)
|
||||
const subjectImg = SUBJECT_IMAGE_MAP[subjectKey] || '/img/math-tutoring.png'
|
||||
|
||||
// 학부모 검색 최적화: [지역] [과목]과외 전문 매칭 | [학년] 1:1 방문 맞춤 수업 (공백 포함 30~35자 내외 말줄임 방지)
|
||||
const pageTitle = `${regionTitle} ${subjectName}과외 전문 매칭 | ${grade} 1:1 방문 맞춤 수업`
|
||||
const pageTitle = isRegionOnly
|
||||
? `${shortSido} 중등 수학 과외 · ${shortSido} 중등 과외 | ${regionTitle} 초·중·고 1:1 맞춤 과외`
|
||||
: `${shortSido} ${gradeShort} ${subjectName} 과외 · ${regionTitle} ${grade} ${subjectName}과외 | ${shortSido} ${gradeShort} 과외 1:1 매칭`
|
||||
|
||||
// 고의도 검색 및 전환 최적화 메타 디스크립션 (과외 비용 시세 + 학교 기출 분석 + 100% 신원 검증 + 무료 시범수업)
|
||||
const pageDescription = `${regionTitle} ${grade} ${subjectName}과외 전문 매칭. 과외 비용 및 시세 비교부터 무료 시범수업 신청까지. ${dong} 인근 학교별 기출 족보 완벽 분석, 서술형 감점 방지, 검증된 1:1 전문 선생님 100% 매칭.`
|
||||
const pageDescription = isRegionOnly
|
||||
? `${shortSido} 중등 수학 과외, ${shortSido} 중등 과외, ${dong} 중등 수학 과외 전문 ${siteName}! ${regionTitle} 초등·중등·고등 국영수사과 1:1 맞춤 과외와 검증된 전문 선생님 무료 시범수업, 과외비 비교를 확인하세요.`
|
||||
: `${shortSido} ${gradeShort} ${subjectName} 과외, ${shortSido} ${gradeShort} 과외, ${dong} ${gradeShort} ${subjectName} 과외 전문 ${siteName}! ${regionTitle} ${grade} ${subjectName} 1:1 방문·화상 맞춤 수업으로 내신·수능 성적 향상을 책임집니다. 과외비 투명 공개 및 무료 시범수업 신청하세요.`
|
||||
|
||||
// 표준 Canonical URL
|
||||
const canonicalUrl = `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(grade)}/${encodeURIComponent(subjectName)}`
|
||||
const dongUrl = `${siteDomain}/${encodeURIComponent(dong)}`
|
||||
const canonicalUrl = isRegionOnly
|
||||
? dongUrl
|
||||
: `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(grade)}/${encodeURIComponent(subjectName)}`
|
||||
|
||||
const jsonLd = {
|
||||
const allBrandImages = [
|
||||
`${siteDomain}/img/og-main.png`,
|
||||
`${siteDomain}/img/math-tutoring.png`,
|
||||
`${siteDomain}/img/english-tutoring.png`,
|
||||
`${siteDomain}/img/korean-tutoring.png`,
|
||||
`${siteDomain}/img/science-tutoring.png`,
|
||||
`${siteDomain}/img/social-studies-tutoring.png`
|
||||
]
|
||||
|
||||
// 서브 라우터 캐러셀(ItemList) 항목 생성: 현재 동의 5대 과목 + 다른 학년(중복 제외 총 7개)
|
||||
const carouselCourses: Array<{ name: string, desc: string, url: string, image: string }> = []
|
||||
|
||||
for (const sub of SUBJECT_LIST) {
|
||||
const cUrl = `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(grade)}/${encodeURIComponent(sub.name)}`
|
||||
carouselCourses.push({
|
||||
name: `${shortSido} ${gradeShort} ${sub.name} 과외 · ${regionTitle} ${grade} ${sub.name}과외 1:1 맞춤 수업`,
|
||||
desc: `${shortSido} ${gradeShort} ${sub.name} 과외 및 ${dong} ${grade} ${sub.name} 내신·수능 대비 — ${sub.desc}`,
|
||||
url: cUrl,
|
||||
image: `${siteDomain}${sub.img}`
|
||||
})
|
||||
}
|
||||
|
||||
for (const g of GRADE_LIST) {
|
||||
if (g !== grade) {
|
||||
const gShort = g === '초등학생' ? '초등' : g === '고등학생' ? '고등' : '중등'
|
||||
const cUrl = `${siteDomain}/${encodeURIComponent(dong)}/${encodeURIComponent(g)}/${encodeURIComponent(subjectName)}`
|
||||
carouselCourses.push({
|
||||
name: `${shortSido} ${gShort} ${subjectName} 과외 · ${regionTitle} ${g} ${subjectName}과외 1:1 맞춤 수업`,
|
||||
desc: `${shortSido} ${gShort} 과외 및 ${dong} ${g} ${subjectName} 내신 1등급 및 취약 단원 밀착 코칭`,
|
||||
url: cUrl,
|
||||
image: `${siteDomain}${subjectImg}`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const breadcrumbItems = isRegionOnly
|
||||
? [
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 1,
|
||||
'name': '홈',
|
||||
'item': `${siteDomain}/`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 2,
|
||||
'name': `${regionTitle} 과외`,
|
||||
'item': dongUrl
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 1,
|
||||
'name': '홈',
|
||||
'item': `${siteDomain}/`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 2,
|
||||
'name': `${dong} 과외`,
|
||||
'item': dongUrl
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 3,
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 (${dong})`,
|
||||
'item': canonicalUrl
|
||||
}
|
||||
]
|
||||
|
||||
// 블록 1: @graph (WebSite + WebPage + ImageObject + EducationalOrganization + LocalBusiness + Course + BreadcrumbList)
|
||||
const jsonLdGraph = {
|
||||
'@context': 'https://schema.org',
|
||||
'@graph': [
|
||||
{
|
||||
'@type': 'EducationalOrganization',
|
||||
'@type': 'WebSite',
|
||||
'@id': `${siteDomain}/#site`,
|
||||
'url': `${siteDomain}/`,
|
||||
'name': siteName,
|
||||
'url': siteDomain,
|
||||
'inLanguage': 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'WebPage',
|
||||
'@id': `${canonicalUrl}#page`,
|
||||
'url': canonicalUrl,
|
||||
'name': pageTitle,
|
||||
'description': pageDescription,
|
||||
'isPartOf': { '@id': `${siteDomain}/#site` },
|
||||
'primaryImageOfPage': { '@id': `${canonicalUrl}#img` },
|
||||
'inLanguage': 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'ImageObject',
|
||||
'@id': `${canonicalUrl}#img`,
|
||||
'url': `${siteDomain}${subjectImg}`,
|
||||
'contentUrl': `${siteDomain}${subjectImg}`,
|
||||
'width': 1080,
|
||||
'height': 1080,
|
||||
'caption': `${shortSido} ${gradeShort} ${subjectName} 과외`
|
||||
},
|
||||
{
|
||||
'@type': 'EducationalOrganization',
|
||||
'@id': `${siteDomain}/#org`,
|
||||
'name': siteName,
|
||||
'url': `${siteDomain}/`,
|
||||
'image': allBrandImages,
|
||||
'description': pageDescription,
|
||||
'telephone': '+82-10-5961-5807',
|
||||
'areaServed': {
|
||||
'@type': 'AdministrativeArea',
|
||||
'name': `${sido} ${sigungu} ${dong}`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Course',
|
||||
'name': `${dong} ${grade} ${subjectName} 1:1 맞춤 과외`,
|
||||
'description': `${dong} 인근 학교 내신 출제 경향 분석 및 ${subjectName} 1등급 도약 커리큘럼`,
|
||||
'provider': {
|
||||
'@type': 'Organization',
|
||||
'name': siteName
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'LocalBusiness',
|
||||
'name': `${regionTitle} 1:1 방문 과외`,
|
||||
'image': `${siteDomain}/img/og-preview.png`,
|
||||
'@id': `${canonicalUrl}#business`,
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 · ${regionTitle} 1:1 방문 과외`,
|
||||
'image': allBrandImages,
|
||||
'url': canonicalUrl,
|
||||
'telephone': '+82-10-5961-5807',
|
||||
'priceRange': '₩₩',
|
||||
'address': {
|
||||
'@type': 'PostalAddress',
|
||||
'addressLocality': sido,
|
||||
'addressRegion': sigungu,
|
||||
'addressLocality': sigungu,
|
||||
'addressRegion': sido,
|
||||
'streetAddress': dong,
|
||||
'addressCountry': 'KR'
|
||||
},
|
||||
'areaServed': `${sido} ${sigungu} ${dong}`
|
||||
},
|
||||
{
|
||||
'@type': 'FAQPage',
|
||||
'mainEntity': [
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${dong} ${grade} ${subjectName} 방문 과외와 온라인 화상 과외 중 어떤 것이 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `학생과 학부모님의 선호에 따라 100% 자택 방문 대면 과외 또는 실시간 쌍방향 비대면 화상 과외 중 자유롭게 선택하실 수 있습니다. ${dong} 전 지역 방문 수업이 가능합니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${grade} ${subjectName} 전문 선생님이 학생과 잘 맞지 않으면 교체 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': '네, 1회 무료 모의수업을 통해 사전에 호흡을 맞추며, 정규 수업 시작 후에도 학생의 성향이나 요청에 따라 추가 비용 없이 100% 무료 교체 및 환불 규정을 보장합니다.'
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${grade} ${subjectName} 과외 수업 비용은 어떻게 되나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${grade} 내신 단계, 주당 수업 횟수, 수업 시간(1회 60분/90분/120분)에 따라 표준 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다. 무료 상담 시 상세 견적표를 안내해 드립니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${dong} 학교 중간·기말고사 직전 단기 ${subjectName} 족보 클리닉도 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, 시험 3~4주 전 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${grade} ${subjectName} 단기 속성 킬러 클리닉 프로그램도 상시 운영 중입니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${subjectName} 외에 다른 과목도 함께 상담받을 수 있나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${subjectName} 집중 신청은 물론, 국영수 또는 수탐 복합 패키지로 맞춤 구성하여 전 과목 플래너 관리와 함께 시간표를 편성하실 수 있습니다.`
|
||||
}
|
||||
}
|
||||
]
|
||||
'@type': 'Course',
|
||||
'@id': `${canonicalUrl}#course`,
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 · ${regionTitle} ${grade} ${subjectName} 1:1 맞춤 과외`,
|
||||
'description': `${shortSido} ${gradeShort} ${subjectName} 과외 및 ${shortSido} ${gradeShort} 과외 전문 매칭 — ${dong} 인근 학교 내신 출제 경향 분석 및 ${subjectName} 1등급 도약 커리큘럼`,
|
||||
'url': canonicalUrl,
|
||||
'image': `${siteDomain}${subjectImg}`,
|
||||
'provider': {
|
||||
'@type': 'Organization',
|
||||
'name': siteName,
|
||||
'sameAs': siteDomain
|
||||
},
|
||||
'offers': {
|
||||
'@type': 'Offer',
|
||||
'category': 'Paid',
|
||||
'priceCurrency': 'KRW',
|
||||
'availability': 'https://schema.org/InStock',
|
||||
'url': canonicalUrl
|
||||
},
|
||||
'hasCourseInstance': {
|
||||
'@type': 'CourseInstance',
|
||||
'courseMode': ['onsite', 'online']
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'BreadcrumbList',
|
||||
'itemListElement': [
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 1,
|
||||
'name': '홈',
|
||||
'item': siteDomain
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 2,
|
||||
'name': sido,
|
||||
'item': `${siteDomain}/${encodeURIComponent(sido)}`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 3,
|
||||
'name': sigungu,
|
||||
'item': `${siteDomain}/${encodeURIComponent(sigungu)}`
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
'position': 4,
|
||||
'name': `${dong} ${subjectName}`,
|
||||
'item': canonicalUrl
|
||||
}
|
||||
]
|
||||
'@id': `${canonicalUrl}#breadcrumb`,
|
||||
'itemListElement': breadcrumbItems
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 블록 2: FAQPage 단독 JSON-LD (정확한 타겟 키워드 Q&A 전면 배치)
|
||||
const jsonLdFaq = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'FAQPage',
|
||||
'mainEntity': [
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외(${dong}), 방문 수업과 온라인 화상 수업 모두 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, ${shortSido} ${gradeShort} ${subjectName} 과외 및 ${shortSido} ${gradeShort} 과외는 학생과 학부모님의 선호에 따라 ${dong} 100% 자택 방문 대면 과외 또는 실시간 쌍방향 화상 과외 중 자유롭게 선택하실 수 있습니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} 과외 및 ${dong} ${gradeShort} ${subjectName} 과외 선생님이 학생과 맞지 않으면 교체 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, ${shortSido} ${gradeShort} ${subjectName} 과외는 1회 무료 시범수업을 통해 사전에 호흡을 맞추며, 정규 수업 시작 후에도 학생 성향이나 요청에 따라 추가 비용 없이 100% 무료 교체 및 환불 규정을 보장합니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외(${dong} ${grade} ${subjectName}과외) 수업 비용은 어떻게 되나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${shortSido} ${gradeShort} ${subjectName} 과외 및 ${shortSido} ${gradeShort} 과외 수업료는 ${grade} 내신 단계, 주당 횟수, 수업 시간(60분/90분/120분)에 따라 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${dong} 학교 중간·기말고사 대비 ${shortSido} ${gradeShort} ${subjectName} 과외 단기 족보 클리닉도 가능한가요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `네, 시험 3~4주 전 ${dong} 인근 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${shortSido} ${gradeShort} ${subjectName} 과외 단기 속성 킬러 클리닉 프로그램도 상시 운영 중입니다.`
|
||||
}
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 외에 다른 과목도 함께 ${shortSido} ${gradeShort} 과외 상담을 받을 수 있나요?`,
|
||||
'acceptedAnswer': {
|
||||
'@type': 'Answer',
|
||||
'text': `${shortSido} ${gradeShort} ${subjectName} 과외 집중 신청은 물론, 국영수 또는 수탐 복합 ${shortSido} ${gradeShort} 과외 패키지로 맞춤 구성하여 전 과목 플래너 관리와 함께 시간표를 편성하실 수 있습니다.`
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 블록 3: ItemList 단독 JSON-LD (최상위 name, url, image + item: Course 동시 제공)
|
||||
const jsonLdItemList = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'ItemList',
|
||||
'name': `${shortSido} ${gradeShort} ${subjectName} 과외 · ${dong} ${gradeShort} 과외`,
|
||||
'itemListElement': carouselCourses.map((c, idx) => ({
|
||||
'@type': 'ListItem',
|
||||
'position': idx + 1,
|
||||
'name': c.name,
|
||||
'url': c.url,
|
||||
'image': c.image,
|
||||
'item': {
|
||||
'@type': 'Course',
|
||||
'name': c.name,
|
||||
'description': c.desc,
|
||||
'url': c.url,
|
||||
'image': c.image,
|
||||
'provider': {
|
||||
'@type': 'Organization',
|
||||
'name': siteName,
|
||||
'sameAs': siteDomain
|
||||
},
|
||||
'offers': {
|
||||
'@type': 'Offer',
|
||||
'category': 'Paid',
|
||||
'priceCurrency': 'KRW',
|
||||
'availability': 'https://schema.org/InStock',
|
||||
'url': c.url
|
||||
},
|
||||
'hasCourseInstance': {
|
||||
'@type': 'CourseInstance',
|
||||
'courseMode': ['onsite', 'online']
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
return {
|
||||
title: pageTitle,
|
||||
meta: [
|
||||
{ name: 'robots', content: 'index,follow' },
|
||||
{ name: 'naver-site-verification', content: 'bfbfcb6ed8c107d05503feed914769a29b07cf06' },
|
||||
{ name: 'description', content: pageDescription },
|
||||
{ name: 'keywords', content: `${dong}과외, ${dong}${subjectName}과외, ${dong}${grade}과외, ${sigungu}과외, ${dong}학원, ${dong}내신대비, ${subjectName}1:1과외` },
|
||||
{ name: 'keywords', content: `${shortSido} ${gradeShort} ${subjectName} 과외, ${shortSido} ${gradeShort} 과외, ${shortSido}${gradeShort}${subjectName}과외, ${shortSido}${gradeShort}과외, ${dong} ${gradeShort} ${subjectName} 과외, ${dong} ${gradeShort} 과외, ${shortSido} 중등 수학 과외, ${shortSido} 중등 과외, ${shortSido} 고등 수학 과외, ${shortSido} 초등 수학 과외, ${regionTitle} ${subjectName}과외, ${dong} ${subjectName}과외, ${dong} ${grade} ${subjectName}과외, ${dong}과외, ${sigungu}과외, ${shortSido}과외` },
|
||||
{ property: 'og:type', content: 'website' },
|
||||
{ property: 'og:locale', content: 'ko_KR' },
|
||||
{ property: 'og:title', content: pageTitle },
|
||||
{ property: 'og:description', content: pageDescription },
|
||||
{ property: 'og:url', content: canonicalUrl },
|
||||
{ property: 'og:site_name', content: siteName },
|
||||
{ property: 'og:image', content: `${siteDomain}/img/og-preview.png` },
|
||||
{ property: 'og:image', content: `${siteDomain}${subjectImg}` },
|
||||
{ property: 'og:image:type', content: 'image/png' },
|
||||
{ property: 'og:image:width', content: '1200' },
|
||||
{ property: 'og:image:height', content: '630' },
|
||||
{ property: 'og:image:alt', content: `${shortSido} ${gradeShort} ${subjectName} 과외 · ${dong} ${gradeShort} ${subjectName} 과외` },
|
||||
{ name: 'twitter:card', content: 'summary_large_image' },
|
||||
{ name: 'twitter:title', content: pageTitle },
|
||||
{ name: 'twitter:description', content: pageDescription }
|
||||
{ name: 'twitter:description', content: pageDescription },
|
||||
{ name: 'twitter:image', content: `${siteDomain}${subjectImg}` }
|
||||
],
|
||||
link: [
|
||||
{ rel: 'canonical', href: canonicalUrl }
|
||||
@@ -152,7 +317,15 @@ export function generateSeoMeta(parsed: ParsedRouteParams, siteName = '새솔 1:
|
||||
script: [
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(jsonLd)
|
||||
children: JSON.stringify(jsonLdGraph)
|
||||
},
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(jsonLdFaq)
|
||||
},
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(jsonLdItemList)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,80 +2,83 @@
|
||||
<section class="faq-section">
|
||||
<div class="section-header">
|
||||
<span class="section-badge">궁금한 점을 풀어드립니다</span>
|
||||
<h2 class="section-title">{{ regionDong }} 1:1 과외 자주 묻는 질문</h2>
|
||||
<h2 class="section-title">{{ shortSidoName }} {{ gradeShortName }} {{ subjectName }} 과외 · {{ regionDong }} 1:1 과외 자주 묻는 질문</h2>
|
||||
<p class="section-desc">학부모님들께서 가장 많이 문의하시는 내용을 모았습니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="faq-list">
|
||||
<div
|
||||
<details
|
||||
v-for="(faq, idx) in faqs"
|
||||
:key="idx"
|
||||
class="faq-item"
|
||||
:class="{ active: openIndex === idx }"
|
||||
class="faq-item qa"
|
||||
:open="idx === 0"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="faq-question"
|
||||
@click="toggle(idx)"
|
||||
:aria-expanded="openIndex === idx"
|
||||
>
|
||||
<summary class="faq-question">
|
||||
<span class="q-icon">Q</span>
|
||||
<span class="q-text">{{ faq.q }}</span>
|
||||
<span class="toggle-icon">{{ openIndex === idx ? '▲' : '▼' }}</span>
|
||||
</button>
|
||||
<div v-show="openIndex === idx" class="faq-answer">
|
||||
<span class="toggle-icon">▼</span>
|
||||
</summary>
|
||||
<div class="faq-answer ans">
|
||||
<span class="a-icon">A</span>
|
||||
<p class="a-text">{{ faq.a }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
regionDong: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
shortSido: {
|
||||
type: String,
|
||||
default: '인천'
|
||||
},
|
||||
grade: {
|
||||
type: String,
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
subjectName: {
|
||||
type: String,
|
||||
default: '영어'
|
||||
default: '수학'
|
||||
}
|
||||
})
|
||||
|
||||
const openIndex = ref(0)
|
||||
|
||||
const toggle = (idx) => {
|
||||
openIndex.value = openIndex.value === idx ? -1 : idx
|
||||
}
|
||||
const shortSidoName = computed(() => props.shortSido || '인천')
|
||||
const gradeShortName = computed(() => {
|
||||
if (props.gradeShort) return props.gradeShort
|
||||
return (props.grade || '').includes('초등') ? '초등' : (props.grade || '').includes('고등') ? '고등' : '중등'
|
||||
})
|
||||
|
||||
const faqs = computed(() => [
|
||||
{
|
||||
q: `${props.regionDong} ${props.grade} ${props.subjectName} 방문 과외와 온라인 화상 과외 중 어떤 것이 가능한가요?`,
|
||||
a: `학생과 학부모님의 선호에 따라 100% 자택 방문 대면 과외 또는 실시간 쌍방향 비대면 화상 과외 중 자유롭게 선택하실 수 있습니다. ${props.regionDong} 전 지역 방문 수업이 가능합니다.`
|
||||
q: `${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외(${props.regionDong}), 방문 수업과 온라인 화상 수업 모두 가능한가요?`,
|
||||
a: `네, ${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외 및 ${shortSidoName.value} ${gradeShortName.value} 과외는 학생과 학부모님의 선호에 따라 ${props.regionDong} 100% 자택 방문 대면 과외 또는 실시간 쌍방향 화상 과외 중 자유롭게 선택하실 수 있습니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.grade} ${props.subjectName} 전문 선생님이 학생과 잘 맞지 않으면 교체 가능한가요?`,
|
||||
a: '네, 1회 무료 모의수업을 통해 사전에 호흡을 맞추며, 정규 수업 시작 후에도 학생의 성향이나 요청에 따라 추가 비용 없이 100% 무료 교체 및 환불 규정을 보장합니다.'
|
||||
q: `${shortSidoName.value} ${gradeShortName.value} 과외 및 ${props.regionDong} ${gradeShortName.value} ${props.subjectName} 과외 선생님이 학생과 맞지 않으면 교체 가능한가요?`,
|
||||
a: `네, ${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외는 1회 무료 시범수업을 통해 사전에 호흡을 맞추며, 정규 수업 시작 후에도 학생 성향이나 요청에 따라 추가 비용 없이 100% 무료 교체 및 환불 규정을 보장합니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.grade} ${props.subjectName} 과외 수업 비용은 어떻게 되나요?`,
|
||||
a: `${props.grade} 내신 단계, 주당 수업 횟수, 수업 시간(1회 60분/90분/120분)에 따라 표준 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다. 무료 상담 시 상세 견적표를 안내해 드립니다.`
|
||||
q: `${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외(${props.regionDong} ${props.grade} ${props.subjectName}과외) 수업 비용은 어떻게 되나요?`,
|
||||
a: `${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외 및 ${shortSidoName.value} ${gradeShortName.value} 과외 수업료는 ${props.grade} 내신 단계, 주당 횟수, 수업 시간(60분/90분/120분)에 따라 교육청 가이드라인에 맞춘 투명한 정찰제로 운영됩니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.regionDong} 학교 중간·기말고사 직전 단기 ${props.subjectName} 족보 클리닉도 가능한가요?`,
|
||||
a: `네, 시험 3~4주 전 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${props.grade} ${props.subjectName} 단기 속성 킬러 클리닉 프로그램도 상시 운영 중입니다.`
|
||||
q: `${props.regionDong} 학교 중간·기말고사 대비 ${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외 단기 족보 클리닉도 가능한가요?`,
|
||||
a: `네, 시험 3~4주 전 ${props.regionDong} 인근 학교별 기출 족보 풀이 및 서술형 배점 방어를 위한 ${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외 단기 속성 킬러 클리닉 프로그램도 상시 운영 중입니다.`
|
||||
},
|
||||
{
|
||||
q: `${props.subjectName} 외에 다른 과목도 함께 상담받을 수 있나요?`,
|
||||
a: `${props.subjectName} 집중 신청은 물론, 국영수 또는 수탐 복합 패키지로 맞춤 구성하여 전 과목 플래너 관리와 함께 시간표를 편성하실 수 있습니다.`
|
||||
q: `${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외 외에 다른 과목도 함께 ${shortSidoName.value} ${gradeShortName.value} 과외 상담을 받을 수 있나요?`,
|
||||
a: `${shortSidoName.value} ${gradeShortName.value} ${props.subjectName} 과외 집중 신청은 물론, 국영수 또는 수탐 복합 ${shortSidoName.value} ${gradeShortName.value} 과외 패키지로 맞춤 구성하여 전 과목 플래너 관리와 함께 시간표를 편성하실 수 있습니다.`
|
||||
}
|
||||
])
|
||||
</script>
|
||||
@@ -143,11 +146,16 @@ const faqs = computed(() => [
|
||||
border: none;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
font-size: clamp(0.9rem, 2.2vw, 1.02rem);
|
||||
font-weight: 800;
|
||||
color: var(--text-color, #0f172a);
|
||||
}
|
||||
|
||||
.faq-question::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.q-icon {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
@@ -172,6 +180,11 @@ const faqs = computed(() => [
|
||||
font-size: 0.8rem;
|
||||
color: #94a3b8;
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.faq-item[open] .toggle-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.faq-answer {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 네이버 5개 멀티 썸네일 스니펫 및 상담 링크 매칭용 5개 리스트 -->
|
||||
<!-- 네이버 5개 멀티 썸네일 스니펫 및 상담 링크 매칭용 가로 5열 캐러셀 리스트 -->
|
||||
<div class="focus-grid">
|
||||
<a
|
||||
v-for="(item, idx) in programList"
|
||||
@@ -21,27 +21,29 @@
|
||||
class="focus-card"
|
||||
:title="`${item.title} 상담 신청`"
|
||||
>
|
||||
<div class="focus-thumb-wrap">
|
||||
<img
|
||||
:src="item.image"
|
||||
:alt="`${item.title} 1:1 맞춤 지도`"
|
||||
width="500"
|
||||
height="500"
|
||||
loading="lazy"
|
||||
class="focus-img"
|
||||
/>
|
||||
<span class="step-tag">STEP 0{{ idx + 1 }}</span>
|
||||
</div>
|
||||
|
||||
<div class="focus-info">
|
||||
<div class="focus-item-tag">{{ item.tag }}</div>
|
||||
<strong class="focus-item-title">{{ item.title }}</strong>
|
||||
<p class="focus-item-desc">{{ item.desc }}</p>
|
||||
<div class="focus-cta-link">
|
||||
<span>1:1 상담 예약</span>
|
||||
<span class="arrow-sym">→</span>
|
||||
<figure class="focus-figure m-0 flex flex-col flex-1">
|
||||
<div class="focus-thumb-wrap">
|
||||
<img
|
||||
:src="item.image"
|
||||
:alt="item.title"
|
||||
width="1080"
|
||||
height="1080"
|
||||
decoding="async"
|
||||
loading="eager"
|
||||
class="focus-img"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<figcaption class="focus-info">
|
||||
<div class="focus-item-tag">{{ item.tag }}</div>
|
||||
<h3 class="focus-item-title m-0">{{ item.title }}</h3>
|
||||
<p class="focus-item-desc">{{ item.desc }}</p>
|
||||
<div class="focus-cta-link">
|
||||
<span>1:1 상담 예약</span>
|
||||
<span class="arrow-sym">→</span>
|
||||
</div>
|
||||
</figcaption>
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -56,6 +58,14 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
shortSido: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
subjectName: {
|
||||
type: String,
|
||||
default: '수학'
|
||||
@@ -78,7 +88,7 @@ const displaySubject = computed(() => {
|
||||
return props.subjectName || '수학'
|
||||
})
|
||||
|
||||
// 초등 vs 중등/고등 5개 항목 분기
|
||||
// 초등 vs 중등/고등 5개 항목 분기 (실사 PNG 5종 적용)
|
||||
const programList = computed(() => {
|
||||
const dong = props.regionDong ? `${props.regionDong} ` : ''
|
||||
const sub = displaySubject.value
|
||||
@@ -90,31 +100,31 @@ const programList = computed(() => {
|
||||
tag: '개념 완성',
|
||||
title: `${dong}초등 ${sub}과외 - 기초학습`,
|
||||
desc: '개념 쏙쏙 이해와 튼튼한 연산 기본기 완성',
|
||||
image: '/images/focus/elem-1-basic.svg'
|
||||
image: '/img/math-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '학습 코칭',
|
||||
title: `${dong}초등 ${sub}과외 - 공부방법`,
|
||||
desc: '스스로 원리를 깨우치는 올바른 문제 해결력',
|
||||
image: '/images/focus/elem-2-method.svg'
|
||||
image: '/img/english-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '밀착 피드백',
|
||||
title: `${dong}초등 ${sub}과외 - 숙제검사`,
|
||||
desc: '매일 1:1 오답 점검과 꼼꼼한 피드백 클리닉',
|
||||
image: '/images/focus/elem-3-homework.svg'
|
||||
image: '/img/korean-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '자기주도',
|
||||
title: `${dong}초등 ${sub}과외 - 공부습관`,
|
||||
desc: '매일 스스로 책상에 앉는 주도적 학습 루틴',
|
||||
image: '/images/focus/elem-4-habit.svg'
|
||||
image: '/img/science-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '상위권 도약',
|
||||
title: `${dong}초등 ${sub}과외 - 중등대비`,
|
||||
desc: '중학교 내신 서술형과 심화 개념 선행 마스터',
|
||||
image: '/images/focus/elem-5-middleprep.svg'
|
||||
image: '/img/social-studies-tutoring.png'
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -125,31 +135,31 @@ const programList = computed(() => {
|
||||
tag: '기출 정복',
|
||||
title: `${dong}${grd} 중간고사 ${sub}과외`,
|
||||
desc: '학교별 기출 족보 완벽 분석 및 서술형 킬러 대비',
|
||||
image: '/images/focus/sec-1-midterm.svg'
|
||||
image: '/img/math-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '학기말 총력',
|
||||
title: `${dong}${grd} 기말고사 ${sub}과외`,
|
||||
desc: '전 범위 오답 분석 및 취약 유형 완벽 클리닉',
|
||||
image: '/images/focus/sec-2-final.svg'
|
||||
image: '/img/english-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '수능·전국연합',
|
||||
title: `${dong}${grd} 모의고사 ${sub}과외`,
|
||||
desc: '수능형 사고력 확장 및 실전 시간 배분 특훈',
|
||||
image: '/images/focus/sec-3-mock.svg'
|
||||
image: '/img/korean-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '내신 만점',
|
||||
title: `${dong}${grd} 수행평가 ${sub}과외`,
|
||||
desc: '조건 감점 0점화 및 과제·보고서 완벽 케어',
|
||||
image: '/images/focus/sec-4-assessment.svg'
|
||||
image: '/img/science-tutoring.png'
|
||||
},
|
||||
{
|
||||
tag: '1등급 집중',
|
||||
title: `${dong}${grd} 내신대비 ${sub}과외`,
|
||||
desc: '관내 교과서·부교재 적중 1:1 맞춤 지도',
|
||||
image: '/images/focus/sec-5-schoolprep.svg'
|
||||
image: '/img/social-studies-tutoring.png'
|
||||
}
|
||||
]
|
||||
})
|
||||
@@ -202,10 +212,10 @@ const programList = computed(() => {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 5열 카드 그리드 */
|
||||
/* 데스크톱: 가로 1열 5칸 균등 그리드 */
|
||||
.focus-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
grid-template-columns: repeat(5, minmax(180px, 1fr));
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
@@ -313,52 +323,22 @@ const programList = computed(() => {
|
||||
transform: translateX(3px);
|
||||
}
|
||||
|
||||
/* 태블릿 및 모바일 반응형 */
|
||||
@media (max-width: 960px) {
|
||||
/* 태블릿 및 모바일 반응형: 가로 스크롤 캐러셀 유지 */
|
||||
@media (max-width: 1024px) {
|
||||
.focus-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.focus-grid {
|
||||
grid-template-columns: 1fr;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x mandatory;
|
||||
gap: 12px;
|
||||
padding-bottom: 12px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.focus-card {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.focus-thumb-wrap {
|
||||
width: 105px;
|
||||
height: 105px;
|
||||
aspect-ratio: 1 / 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.focus-info {
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.focus-item-title {
|
||||
font-size: 0.88rem;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.focus-item-desc {
|
||||
font-size: 0.74rem;
|
||||
margin-bottom: 6px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.focus-cta-link {
|
||||
padding-top: 4px;
|
||||
font-size: 0.72rem;
|
||||
flex: 0 0 220px;
|
||||
scroll-snap-align: start;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<header class="hero-banner-clean bg-white border-b border-slate-200/80 pt-10 sm:pt-14 pb-14 sm:pb-18 px-4 sm:px-6 relative overflow-hidden text-center">
|
||||
<section class="hero-banner hero-banner-clean bg-white border-b border-slate-200/80 pt-10 sm:pt-14 pb-14 sm:pb-18 px-4 sm:px-6 relative overflow-hidden text-center" itemscope itemtype="https://schema.org/Course">
|
||||
|
||||
<!-- 은은한 상단 엠비언트 라이트 -->
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-blue-50/40 via-transparent to-transparent pointer-events-none"></div>
|
||||
@@ -12,16 +12,20 @@
|
||||
<span>{{ region.dong }} 학군 전담 | 서울대·연고대 및 베테랑 강사진 100% 신원 보증</span>
|
||||
</div>
|
||||
|
||||
<!-- SEO 메인 H1 (사용자 지정 롱테일 조합형: [지역] + [학년] + [과목]과외 + 검증된 전문 선생님 100% 매칭) -->
|
||||
<h1 class="text-2xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.22] sm:leading-[1.18] mb-4">
|
||||
<span>{{ displayRegionName }} {{ grade }} {{ subjectName }}과외</span><br />
|
||||
<span class="text-blue-600">우리 아이 맞춤 검증된 전문 선생님 100% 매칭</span>
|
||||
<!-- 네이버 상위 노출 순서: 1. H1 ➔ 2. meta ➔ 3. H2 ➔ 4. 일반글 P -->
|
||||
<h1 itemprop="headline" class="text-2xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.22] sm:leading-[1.18] mb-3">
|
||||
<span class="highlight text-blue-600">{{ shortSidoName }} {{ gradeShortName }} {{ subjectName }} 과외 · {{ region.dong }} {{ grade }} {{ subjectName }}과외</span><br />
|
||||
1:1 맞춤 학습으로 성적 역전!
|
||||
</h1>
|
||||
|
||||
<!-- 서브 카피 (비용 시세 비교 + 학교 기출 분석 + 무료 시범수업 신뢰 트리거) -->
|
||||
<p class="text-xs sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-7">
|
||||
{{ region.dong }} 인근 학교별 기출 분석부터 과외 비용·시세 비교, 취약 개념 클리닉까지.<br class="hidden sm:inline" />
|
||||
직접 수업받아보고 결정하는 <strong>1:1 무료 방문·화상 시범수업</strong>을 신청하세요.
|
||||
<meta itemprop="name" :content="`${shortSidoName} ${gradeShortName} ${subjectName} 과외 · ${shortSidoName} ${gradeShortName} 과외 (${region.dong})`" />
|
||||
<meta itemprop="description" :content="`${shortSidoName} ${gradeShortName} ${subjectName} 과외 및 ${shortSidoName} ${gradeShortName} 과외 전문 매칭. ${displayRegionName} ${grade} ${subjectName} 1:1 방문·화상 맞춤 수업`" />
|
||||
<meta itemprop="keywords" :content="`${shortSidoName} ${gradeShortName} ${subjectName} 과외, ${shortSidoName} ${gradeShortName} 과외, ${region.dong} ${gradeShortName} ${subjectName} 과외, ${region.dong} ${gradeShortName} 과외, ${displayRegionName} ${grade} ${subjectName}과외`" />
|
||||
<meta itemprop="image" content="/img/math-tutoring.png" />
|
||||
<h2 class="hero-subtitle">
|
||||
{{ shortSidoName }} {{ gradeShortName }} 과외 · {{ displayRegionName }} {{ gradeShortName }} {{ subjectName }} 과외 검증된 전문 선생님 1:1 매칭
|
||||
</h2>
|
||||
<p class="sub-headline text-xs sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-7">
|
||||
{{ shortSidoName }} {{ gradeShortName }} {{ subjectName }} 과외 및 {{ shortSidoName }} {{ gradeShortName }} 과외를 찾으시는 학부모님을 위해 {{ region.dong }} 인근 학교별 기출 족보 분석부터 개인별 취약 개념 완벽 보완, 투명한 과외비 안내와 무료 시범수업까지 1:1 밀착 커리큘럼을 제공합니다.
|
||||
</p>
|
||||
|
||||
<!-- 4대 핵심 신뢰 지표 바 -->
|
||||
@@ -84,15 +88,15 @@
|
||||
|
||||
<!-- 태그 목록 -->
|
||||
<div class="flex justify-center flex-wrap gap-1.5">
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ shortSidoName }}{{ gradeShortName }}{{ subjectName }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ shortSidoName }}{{ gradeShortName }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ region.dong }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ region.dong }}{{ subjectName }}과외</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#{{ grade }}내신대비</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#과외비용시세</span>
|
||||
<span class="text-[11px] px-2.5 py-1 bg-slate-100 border border-slate-200 text-slate-600 rounded-md font-medium">#1대1무료시범수업</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</header>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -111,12 +115,26 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
subjectName: {
|
||||
type: String,
|
||||
default: '수학'
|
||||
}
|
||||
})
|
||||
|
||||
const shortSidoName = computed(() => {
|
||||
const s = (props.region?.sido || '').replace(/특별시|광역시|특별자치시|도/g, '').trim()
|
||||
return s || '인천'
|
||||
})
|
||||
|
||||
const gradeShortName = computed(() => {
|
||||
if (props.gradeShort) return props.gradeShort
|
||||
return props.grade === '초등학생' ? '초등' : props.grade === '고등학생' ? '고등' : '중등'
|
||||
})
|
||||
|
||||
const noticeIdx = ref(0)
|
||||
let timer = null
|
||||
|
||||
@@ -171,4 +189,12 @@ const displayRegionName = computed(() => {
|
||||
.hero-banner-clean {
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-size: 1.15rem;
|
||||
font-weight: 700;
|
||||
color: #334155;
|
||||
margin-bottom: 0.75rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -116,15 +116,15 @@ const nearbyDongs = computed(() => {
|
||||
}
|
||||
|
||||
// 만약 동일 구의 동이 부족하면 전체에서 다른 동 가져오기
|
||||
if (candidates.length < 5) {
|
||||
if (candidates.length < 12) {
|
||||
const others = allList
|
||||
.filter(r => r.dong !== curDong && !candidates.includes(r.dong))
|
||||
.map(r => r.dong)
|
||||
candidates = [...candidates, ...others]
|
||||
}
|
||||
|
||||
// 중복 제거 후 6개 반환
|
||||
return Array.from(new Set(candidates)).slice(0, 6)
|
||||
// 중복 제거 후 12개 반환
|
||||
return Array.from(new Set(candidates)).slice(0, 12)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 2 - 2 - 1 그리드 정렬 레이아웃 -->
|
||||
<!-- 가로 1열 5칸 캐러셀 레이아웃 -->
|
||||
<div class="subject-grid-221">
|
||||
<div
|
||||
v-for="(item, idx) in subjectList"
|
||||
@@ -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"
|
||||
class="subject-img"
|
||||
loading="lazy"
|
||||
loading="eager"
|
||||
fetchpriority="high"
|
||||
/>
|
||||
<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,13 +88,13 @@
|
||||
<!-- 모달 좌측: 고해상도 생성 이미지 원본 -->
|
||||
<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} 과외`"
|
||||
width="1080"
|
||||
height="1080"
|
||||
decoding="async"
|
||||
class="modal-main-img"
|
||||
/>
|
||||
<span class="modal-img-badge">{{ selectedItem.tag }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 모달 우측: 상세 설명 및 액션 버튼 -->
|
||||
@@ -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({
|
||||
@@ -156,9 +157,17 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
shortSido: {
|
||||
type: String,
|
||||
default: '인천'
|
||||
},
|
||||
grade: {
|
||||
type: String,
|
||||
default: '중·고등'
|
||||
default: '중학생'
|
||||
},
|
||||
gradeShort: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
currentSubject: {
|
||||
type: String,
|
||||
@@ -167,15 +176,21 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const defaultDong = '송도동'
|
||||
const defaultSido = '인천'
|
||||
const computedGradeShort = computed(() => {
|
||||
if (props.gradeShort) return props.gradeShort
|
||||
return (props.grade || '').includes('초등') ? '초등' : (props.grade || '').includes('고등') ? '고등' : '중등'
|
||||
})
|
||||
|
||||
const config = useRuntimeConfig()
|
||||
const siteDomain = config.public?.siteDomain || 'https://aeseo.cloud'
|
||||
const siteDomain = config.public?.siteDomain || 'https://aeseo.site'
|
||||
|
||||
// 5대 핵심 과목 (2 2 1 순서 배치)
|
||||
// 5대 핵심 과목 (가로 1열 5칸 캐러셀 배치)
|
||||
const subjectList = [
|
||||
// 1행: 수학, 영어
|
||||
{
|
||||
name: '수학과외',
|
||||
keyName: '수학',
|
||||
subjectKey: 'math',
|
||||
tag: '인기 1위',
|
||||
image: `${siteDomain}/img/math-tutoring.png`,
|
||||
@@ -190,6 +205,7 @@ const subjectList = [
|
||||
},
|
||||
{
|
||||
name: '영어과외',
|
||||
keyName: '영어',
|
||||
subjectKey: 'english',
|
||||
tag: '내신 필수',
|
||||
image: `${siteDomain}/img/english-tutoring.png`,
|
||||
@@ -202,9 +218,9 @@ const subjectList = [
|
||||
{ title: '1:1 구문 독해 & 빈칸 추론 특훈', desc: '문장 구조 분석을 통해 킬러 빈칸·순서 배열 문제를 빠르고 정확히 풉니다.' }
|
||||
]
|
||||
},
|
||||
// 2행: 국어, 과학
|
||||
{
|
||||
name: '국어과외',
|
||||
keyName: '국어',
|
||||
subjectKey: 'korean',
|
||||
tag: '문해력 완성',
|
||||
image: `${siteDomain}/img/korean-tutoring.png`,
|
||||
@@ -219,6 +235,7 @@ const subjectList = [
|
||||
},
|
||||
{
|
||||
name: '과학과외',
|
||||
keyName: '과학',
|
||||
subjectKey: 'science',
|
||||
tag: '통합과학',
|
||||
image: `${siteDomain}/img/science-tutoring.png`,
|
||||
@@ -231,9 +248,9 @@ const subjectList = [
|
||||
{ title: '수행평가 실험 보고서 1:1 가이드', desc: '지필고사뿐 아니라 감점되기 쉬운 과학 탐구 보고서 만점을 케어합니다.' }
|
||||
]
|
||||
},
|
||||
// 3행: 사회 (1개 단독 센터 정렬)
|
||||
{
|
||||
name: '사회과외',
|
||||
keyName: '사회',
|
||||
subjectKey: 'social',
|
||||
tag: '통합사회',
|
||||
image: `${siteDomain}/img/social-studies-tutoring.png`,
|
||||
@@ -304,8 +321,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: '영어',
|
||||
@@ -347,7 +365,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,7 +376,7 @@ 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, 44px) clamp(16px, 3vw, 32px);
|
||||
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.05);
|
||||
}
|
||||
|
||||
@@ -398,31 +416,29 @@ onUnmounted(() => {
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
/* 2 - 2 - 1 그리드 레이아웃 */
|
||||
/* 데스크톱: 가로 1열 5칸 균등 그리드 */
|
||||
.subject-grid-221 {
|
||||
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;
|
||||
grid-column: auto;
|
||||
width: 100%;
|
||||
max-width: calc(50% - 10px);
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.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);
|
||||
@@ -459,14 +475,14 @@ onUnmounted(() => {
|
||||
|
||||
.subject-tag {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
left: 14px;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
background: rgba(15, 23, 42, 0.85);
|
||||
backdrop-filter: blur(4px);
|
||||
color: #ffffff;
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 800;
|
||||
padding: 4px 12px;
|
||||
padding: 3px 10px;
|
||||
border-radius: 9999px;
|
||||
z-index: 2;
|
||||
}
|
||||
@@ -490,9 +506,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 +523,7 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.card-info {
|
||||
padding: 18px 20px;
|
||||
padding: 14px 14px 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
@@ -516,59 +532,68 @@ 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: 1.05rem;
|
||||
font-weight: 800;
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.sub-grade {
|
||||
font-size: 0.78rem;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
color: #64748b;
|
||||
background: #f1f5f9;
|
||||
padding: 2px 8px;
|
||||
padding: 2px 7px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.card-subject-desc {
|
||||
font-size: 0.85rem;
|
||||
font-size: 0.8rem;
|
||||
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.78rem;
|
||||
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: 9px;
|
||||
}
|
||||
|
||||
/* 모바일 반응형 대응 */
|
||||
@media (max-width: 640px) {
|
||||
/* 태블릿/모바일: 가로 스크롤 캐러셀 */
|
||||
@media (max-width: 1024px) {
|
||||
.subject-grid-221 {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x mandatory;
|
||||
gap: 12px;
|
||||
padding-bottom: 12px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
|
||||
.gallery-card {
|
||||
flex: 0 0 220px;
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
|
||||
.card-item-5 {
|
||||
grid-column: auto;
|
||||
max-width: 100%;
|
||||
justify-self: stretch;
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,30 +3,32 @@
|
||||
<!-- 1. 클린 미니멀 프리미엄 네비게이션 헤더 (기본 홈과 동일) -->
|
||||
<AppHeader :siteName="siteName" />
|
||||
|
||||
<!-- 2. 세련된 지역 센터 식별 서브 바 (모던 칩 배너) -->
|
||||
<div class="bg-blue-50/70 border-b border-blue-100/70 py-2.5 px-4">
|
||||
<!-- 2. 더세이브 방식 시맨틱 브레드크럼 및 지역 센터 식별 서브 바 -->
|
||||
<nav class="bc bg-blue-50/70 border-b border-blue-100/70 py-2.5 px-4" aria-label="현재 위치">
|
||||
<div class="max-w-4xl mx-auto flex items-center justify-between flex-wrap gap-2 text-xs">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-1.5 flex-wrap text-slate-600">
|
||||
<NuxtLink to="/" class="font-semibold text-blue-700 hover:underline">홈</NuxtLink>
|
||||
<span class="text-slate-400">›</span>
|
||||
<NuxtLink :to="`/${encodeURIComponent(parsed.dong)}`" class="hover:underline">{{ parsed.dong }} 과외</NuxtLink>
|
||||
<span class="text-slate-400">›</span>
|
||||
<strong class="font-bold text-slate-900">{{ parsed.shortSido }} {{ parsed.gradeShort }} {{ parsed.subjectName }} 과외</strong>
|
||||
</div>
|
||||
<div class="hidden sm:flex items-center gap-1.5 text-slate-500 font-medium">
|
||||
<span class="inline-flex items-center gap-1 font-bold text-blue-700 bg-white px-2.5 py-0.5 rounded-full border border-blue-200/80 shadow-xs">
|
||||
<i class="fa-solid fa-location-dot text-blue-600 text-[10px]"></i>
|
||||
{{ parsed.shortRegionName }} 센터
|
||||
</span>
|
||||
<span class="text-slate-600 font-medium">
|
||||
{{ parsed.dong }} ({{ parsed.sigungu }}) 관내 초·중·고 1:1 맞춤 전담
|
||||
</span>
|
||||
</div>
|
||||
<div class="hidden sm:flex items-center gap-1 text-slate-500 font-medium">
|
||||
<i class="fa-solid fa-shield-check text-emerald-600 text-xs"></i>
|
||||
<span>검증된 전문 선생님 100% 매칭</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- 3. 상단 히어로 배너 (H1 태그 포함) -->
|
||||
<!-- 3. 상단 히어로 배너 (H1 ➔ meta ➔ H2 ➔ P) -->
|
||||
<HeroBanner
|
||||
:region="parsed.region"
|
||||
:shortRegionName="parsed.shortRegionName"
|
||||
:grade="parsed.grade"
|
||||
:grade-short="parsed.gradeShort"
|
||||
:subjectName="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -63,24 +65,30 @@
|
||||
<!-- 9. 수업 진행 4단계 절차 안내 -->
|
||||
<ProcessGuide />
|
||||
|
||||
<!-- 10. 자주 묻는 질문 (FAQ) -->
|
||||
<!-- 10. 자주 묻는 질문 (FAQ - details/summary 시맨틱 구조) -->
|
||||
<FaqAccordion
|
||||
:regionDong="parsed.dong"
|
||||
:shortSido="parsed.shortSido"
|
||||
:grade="parsed.grade"
|
||||
:gradeShort="parsed.gradeShort"
|
||||
:subjectName="parsed.subjectName"
|
||||
/>
|
||||
|
||||
<!-- 11. 네이버 5개 멀티 이미지 매칭용 핵심 과외 프로그램 빠른 보기 -->
|
||||
<FastConsultFocus
|
||||
:regionDong="parsed.dong"
|
||||
:shortSido="parsed.shortSido"
|
||||
:grade="parsed.grade"
|
||||
:gradeShort="parsed.gradeShort"
|
||||
:subjectName="parsed.subjectName"
|
||||
/>
|
||||
|
||||
<!-- 12. 과목별 1타 강사진 갤러리 캐러셀 (클릭 시 페이지 모달 확대 및 상담 연동) -->
|
||||
<SubjectCarousel
|
||||
:regionDong="parsed.dong"
|
||||
:shortSido="parsed.shortSido"
|
||||
:grade="parsed.grade"
|
||||
:gradeShort="parsed.gradeShort"
|
||||
:currentSubject="parsed.subjectName"
|
||||
/>
|
||||
|
||||
@@ -97,13 +105,11 @@
|
||||
:defaultGrade="parsed.grade"
|
||||
:defaultSubject="parsed.subjectName"
|
||||
/>
|
||||
|
||||
<!-- 14. 클린 사이트 푸터 -->
|
||||
<AppFooter />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { parseRouteSlug, getCurriculumBySubject, getAllSubjectsList, getPopularRegions } from '~/utils/dataHelper'
|
||||
import { generateSeoMeta } from '~/utils/seoHelper'
|
||||
@@ -113,27 +119,26 @@ const config = useRuntimeConfig()
|
||||
const siteName = config.public?.siteName || '튜터온'
|
||||
|
||||
// URL 파라미터 파싱
|
||||
const slug = route.params.slug
|
||||
const parsed = parseRouteSlug(slug)
|
||||
const parsed = computed(() => parseRouteSlug(route.params.slug))
|
||||
|
||||
// 커리큘럼 데이터 로드
|
||||
const curriculum = getCurriculumBySubject(parsed.subjectKey)
|
||||
const curriculum = computed(() => getCurriculumBySubject(parsed.value.subjectKey))
|
||||
const allSubjects = getAllSubjectsList()
|
||||
const popularRegions = getPopularRegions(12)
|
||||
|
||||
// 네이버 Yeti 봇 100% 대응 SEO 메타태그 설정
|
||||
const seo = generateSeoMeta(
|
||||
parsed,
|
||||
const seo = computed(() => generateSeoMeta(
|
||||
parsed.value,
|
||||
config.public.siteName,
|
||||
config.public.siteDomain
|
||||
)
|
||||
))
|
||||
|
||||
useHead({
|
||||
title: seo.title,
|
||||
meta: seo.meta,
|
||||
link: seo.link,
|
||||
script: seo.script
|
||||
})
|
||||
useHead(() => ({
|
||||
title: seo.value.title,
|
||||
meta: seo.value.meta,
|
||||
link: seo.value.link,
|
||||
script: seo.value.script
|
||||
}))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<!-- 1. Header (클린 미니멀 프리미엄 네비게이션) -->
|
||||
<header class="bg-white/95 backdrop-blur-md border-b border-slate-200/80 sticky top-0 z-40 w-full transition-all">
|
||||
<div class="max-w-6xl mx-auto px-4 sm:px-6 py-3.5 flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<NuxtLink to="/" class="flex items-center gap-3">
|
||||
<div class="w-9 h-9 rounded-xl bg-blue-600 flex items-center justify-center text-white font-extrabold text-base shadow-sm">
|
||||
T
|
||||
{{ siteName.charAt(0) }}
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-extrabold text-lg sm:text-xl tracking-tight text-slate-900">{{ siteName }}</span>
|
||||
@@ -14,7 +14,7 @@
|
||||
교육청 등록 협력
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<a href="tel:010-5961-5807" class="hidden sm:flex items-center gap-1.5 text-sm font-semibold text-slate-600 hover:text-blue-600 transition">
|
||||
@@ -32,8 +32,8 @@
|
||||
<!-- 2. Main Body -->
|
||||
<main class="w-full pb-20">
|
||||
|
||||
<!-- 히어로 섹션 (AI 스타일 형광/물결 제거, 정제된 모던 에듀테크 캔버스) -->
|
||||
<section class="w-full bg-white border-b border-slate-200/80 pt-12 sm:pt-16 pb-20 px-4 sm:px-6 text-center relative overflow-hidden">
|
||||
<!-- 히어로 섹션 (네이버 상위 노출 DOM 순서: H1 ➔ meta ➔ H2 ➔ P) -->
|
||||
<section class="hero-section w-full bg-white border-b border-slate-200/80 pt-12 sm:pt-16 pb-20 px-4 sm:px-6 text-center relative overflow-hidden" itemscope itemtype="https://schema.org/EducationalOrganization">
|
||||
|
||||
<!-- 은은한 상단 엠비언트 라이트 (절제된 디자이너 톤) -->
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-blue-50/40 via-transparent to-transparent pointer-events-none"></div>
|
||||
@@ -46,16 +46,27 @@
|
||||
<span>인천 전지역 전담 | 명문대 및 베테랑 전문 강사진 100% 신원 보증</span>
|
||||
</div>
|
||||
|
||||
<!-- 메인 H1 (검색 상위 노출 30자 규격 및 학부모 고의도 롱테일 키워드) -->
|
||||
<h1 class="text-3xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.2] sm:leading-[1.18] mb-4">
|
||||
인천 초·중·고 1:1 맞춤 과외 매칭<br class="hidden sm:inline" />
|
||||
<span class="text-blue-600">검증된 전문 선생님 100% 매칭</span>
|
||||
<!-- 1. H1 -->
|
||||
<h1 itemprop="headline" class="text-3xl sm:text-4xl md:text-5xl font-extrabold tracking-tight text-slate-900 leading-[1.2] sm:leading-[1.18] mb-3">
|
||||
인천 중등 수학 과외 · 초·중·고 1:1 맞춤 과외 매칭<br class="hidden sm:inline" />
|
||||
<span class="text-blue-600">내신·수능 성적 향상의 시작</span>
|
||||
</h1>
|
||||
|
||||
<!-- 서브 헤드라인 (비용 시세 비교 + 무료 시범수업 신뢰 트리거) -->
|
||||
<p class="text-sm sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-8">
|
||||
과외 비용·시세 투명 비교부터 무료 시범수업 신청까지.<br class="hidden sm:inline" />
|
||||
인천 관내 학교별 기출 족보를 완벽 분석하여 <strong>내신 1등급 역전 솔루션</strong>을 제공합니다.
|
||||
<!-- 2. meta (마이크로데이터) -->
|
||||
<meta itemprop="name" :content="`${siteName} - 인천 중등 수학 과외 · 인천 중등 과외 1:1 매칭`" />
|
||||
<meta itemprop="description" content="인천 중등 수학 과외, 인천 중등 과외부터 초등·고등 국영수사과 1:1 방문·화상 맞춤 과외 매칭 및 과외비 투명 비교" />
|
||||
<meta itemprop="keywords" content="인천 중등 수학 과외, 인천 중등 과외, 인천 고등 수학 과외, 인천 고등 과외, 인천 초등 수학 과외, 인천 초등 과외, 인천 중등 영어 과외, 인천 과외, 송도동 과외" />
|
||||
<meta itemprop="image" :content="`${siteDomain}/img/math-tutoring.png`" />
|
||||
<link itemprop="url" :href="`${siteDomain}/`" />
|
||||
|
||||
<!-- 3. H2 -->
|
||||
<h2 class="hero-subtitle text-base sm:text-lg font-bold text-slate-700 mb-3">
|
||||
인천 중등 과외 · 초등·고등 국영수사과 검증된 전문 선생님 100% 1:1 매칭
|
||||
</h2>
|
||||
|
||||
<!-- 4. 일반글 P -->
|
||||
<p class="hero-desc text-sm sm:text-base text-slate-600 font-normal max-w-2xl mx-auto leading-relaxed mb-8">
|
||||
인천 중등 수학 과외 및 인천 중등 과외, 초등·고등 전 과목 과외 비용·시세 투명 비교부터 검증된 전문 선생님 무료 시범수업까지 학생에게 꼭 맞는 1:1 맞춤 수업을 제공합니다.
|
||||
</p>
|
||||
|
||||
<!-- 4대 핵심 신뢰 보증 지표 (Trust Bar) -->
|
||||
@@ -400,29 +411,31 @@
|
||||
</section>
|
||||
|
||||
<!-- 5. 과목별 1:1 맞춤과외 갤러리 캐러셀 (클릭 시 확대 모달 및 상담/이동) -->
|
||||
<SubjectCarousel grade="초·중·고" />
|
||||
<SubjectCarousel :regionDong="defaultDong" shortSido="인천" grade="중학생" gradeShort="중등" />
|
||||
|
||||
<!-- 6. FAQ 섹션 (정돈된 아코디언) -->
|
||||
<!-- 6. FAQ 섹션 (더세이브 방식 네이티브 details/summary 시맨틱 구조) -->
|
||||
<section class="mt-16 px-4 sm:px-6 max-w-4xl mx-auto">
|
||||
<header class="text-center mb-8">
|
||||
<span class="text-xs sm:text-sm font-bold text-slate-400 tracking-wider">FAQ</span>
|
||||
<h2 class="text-2xl sm:text-3xl font-extrabold text-slate-900 mt-1 tracking-tight">자주 묻는 질문</h2>
|
||||
<h2 class="text-2xl sm:text-3xl font-extrabold text-slate-900 mt-1 tracking-tight">인천 1:1 맞춤 과외 자주 묻는 질문</h2>
|
||||
<p class="text-xs sm:text-sm text-slate-500 mt-1">인천 학부모님들께서 가장 많이 문의하시는 과외 진행 절차입니다.</p>
|
||||
</header>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div v-for="(faq, idx) in faqs" :key="idx" class="border border-slate-200 rounded-xl overflow-hidden bg-white shadow-xs">
|
||||
<button @click="faq.open = !faq.open" class="w-full p-4 sm:p-5 text-left text-sm sm:text-base font-bold text-slate-800 flex justify-between items-center hover:bg-slate-50 transition">
|
||||
<details v-for="(faq, idx) in faqs" :key="idx" :open="idx === 0" class="qa border border-slate-200 rounded-xl overflow-hidden bg-white shadow-xs group">
|
||||
<summary class="w-full p-4 sm:p-5 text-left text-sm sm:text-base font-bold text-slate-800 cursor-pointer list-none flex justify-between items-center hover:bg-slate-50 transition">
|
||||
<span>{{ faq.q }}</span>
|
||||
<i class="fa-solid fa-chevron-down text-xs sm:text-sm text-slate-400 transition-transform" :class="{ 'rotate-180': faq.open }"></i>
|
||||
</button>
|
||||
<div v-show="faq.open" class="p-4 sm:p-5 pt-0 text-xs sm:text-sm text-slate-600 leading-relaxed border-t border-slate-100 bg-slate-50/50">
|
||||
<i class="fa-solid fa-chevron-down text-xs sm:text-sm text-slate-400 transition-transform group-open:rotate-180"></i>
|
||||
</summary>
|
||||
<div class="ans p-4 sm:p-5 pt-0 text-xs sm:text-sm text-slate-600 leading-relaxed border-t border-slate-100 bg-slate-50/50">
|
||||
{{ faq.a }}
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<InternalLinkHub :regionDong="defaultDong" grade="중학생" subjectName="수학" />
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
@@ -434,6 +447,7 @@ import { ref, reactive, computed, onMounted } from 'vue'
|
||||
const config = useRuntimeConfig()
|
||||
const siteName = config.public.siteName || '튜터온'
|
||||
const siteDomain = config.public.siteDomain || 'https://aeseo.site'
|
||||
const defaultDong = '송도동'
|
||||
|
||||
const isSubmitting = ref(false)
|
||||
const submitSuccess = ref(false)
|
||||
@@ -500,7 +514,7 @@ onMounted(() => {
|
||||
}
|
||||
});
|
||||
}
|
||||
formData.grade = currentGradeOptions.value[1] || currentGradeOptions.value[0]
|
||||
formData.grade = currentGradeOptions.value[1] || currentGradeOptions.value[0]
|
||||
setInterval(() => {
|
||||
rollingIdx = (rollingIdx + 1) % rollingMessages.length
|
||||
currentNotice.value = rollingMessages[rollingIdx]
|
||||
@@ -548,24 +562,20 @@ function formatPhone(e) {
|
||||
|
||||
const faqs = reactive([
|
||||
{
|
||||
q: '무료 시범수업은 어떻게 진행되나요?',
|
||||
a: '신청서 접수 후 인천 전담 매니저가 유선으로 학생의 성향과 목표를 파악한 뒤, 가장 적합한 전문 선생님을 배정해 드립니다. 배정된 선생님이 1:1 방문 또는 화상으로 40~50분간 모의 수업 및 취약점 진단을 무료로 진행하며, 수업 후 계속 진행 여부를 편안하게 결정하실 수 있습니다.',
|
||||
open: true
|
||||
q: '인천 중등 수학 과외 및 인천 중등 과외 무료 시범수업은 어떻게 진행되나요?',
|
||||
a: '신청서 접수 후 인천 전담 매니저가 유선으로 학생의 성향과 목표를 파악한 뒤, 인천 초·중·고 과외 전문 선생님을 배정해 드립니다. 배정된 선생님이 1:1 방문 또는 화상으로 40~50분간 모의 수업 및 취약점 진단을 무료로 진행하며, 수업 후 계속 진행 여부를 편안하게 결정하실 수 있습니다.'
|
||||
},
|
||||
{
|
||||
q: '과외 비용 및 시세는 어떻게 되나요?',
|
||||
a: '학년(초등/중등/고등)과 주당 수업 횟수(주 1회, 주 2회 등), 수업 시간(회당 60분~120분)에 따라 교육청 가이드라인에 맞춘 투명한 표준 시세로 책정됩니다. 상담 시 거품 없는 정확한 우리 동네 과외 비용을 안내해 드립니다.',
|
||||
open: false
|
||||
q: '인천 중등 수학 과외 · 인천 초·중·고 과외 비용 및 시세는 어떻게 되나요?',
|
||||
a: '인천 중등 과외 및 초등·고등 과외 비용은 학년과 주당 수업 횟수(주 1회, 주 2회 등), 수업 시간(회당 60분~120분)에 따라 교육청 가이드라인에 맞춘 투명한 표준 시세로 책정됩니다. 상담 시 거품 없는 정확한 우리 동네 과외 비용을 안내해 드립니다.'
|
||||
},
|
||||
{
|
||||
q: '선생님 신원과 학력 검증은 어떻게 이루어지나요?',
|
||||
a: '모든 강사진은 주민등록초본, 대학/대학원 재학 및 졸업증명서, 성범죄 경력 조회 등 엄격한 4단계 서류 검증과 교육청 개인과외교습자 신고를 100% 완료한 검증된 전문 선생님입니다.',
|
||||
open: false
|
||||
q: '인천 중등 과외 선생님 신원과 학력 검증은 어떻게 이루어지나요?',
|
||||
a: '인천 중등 수학 과외 및 인천 초·중·고 과외 모든 강사진은 주민등록초본, 대학/대학원 재학 및 졸업증명서, 성범죄 경력 조회 등 엄격한 4단계 서류 검증과 교육청 개인과외교습자 신고를 100% 완료한 검증된 전문 선생님입니다.'
|
||||
},
|
||||
{
|
||||
q: '선생님이 아이와 맞지 않으면 어떻게 하나요?',
|
||||
a: '무료 시범수업을 통해 사전에 호흡을 맞출 수 있으며, 정규 수업 진행 중에도 선생님 교체를 희망하시면 추가 비용 없이 100% 만족하실 때까지 새로운 선생님으로 무료 재매칭을 진행해 드립니다.',
|
||||
open: false
|
||||
q: '인천 중등 수학 과외 선생님이 아이와 맞지 않으면 교체가 가능한가요?',
|
||||
a: '네, 인천 중등 과외 무료 시범수업을 통해 사전에 호흡을 맞출 수 있으며, 정규 수업 진행 중에도 선생님 교체를 희망하시면 추가 비용 없이 100% 만족하실 때까지 새로운 선생님으로 무료 재매칭을 진행해 드립니다.'
|
||||
}
|
||||
])
|
||||
|
||||
@@ -605,49 +615,97 @@ async function handleSubmit() {
|
||||
}
|
||||
}
|
||||
|
||||
// SEO 태그 설정 (사용자 가이드 30~35자 내외 글자 수 및 고의도 롱테일 키워드 100% 준수)
|
||||
// SEO 태그 및 소셜 메타데이터 (네이버/구글 검색 최적화 및 3종 구조화 데이터 JSON-LD)
|
||||
const homeCanonical = siteDomain.endsWith('/') ? siteDomain : `${siteDomain}/`
|
||||
const homeTitle = `인천 중등 수학 과외 · 인천 중등 과외 | 초·중·고 1:1 맞춤 과외 ${siteName}`
|
||||
const homeDesc = `인천 중등 수학 과외, 인천 중등 과외, ${defaultDong} 중등 수학 과외 전문 ${siteName}! 초·중·고 국영수사과 과외 비용·시세 투명 비교부터 검증된 전문 선생님 무료 시범수업 신청까지 1:1 맞춤 솔루션`
|
||||
const allBrandImages = [
|
||||
`${siteDomain}/img/og-main.png`,
|
||||
`${siteDomain}/img/math-tutoring.png`,
|
||||
`${siteDomain}/img/english-tutoring.png`,
|
||||
`${siteDomain}/img/korean-tutoring.png`,
|
||||
`${siteDomain}/img/science-tutoring.png`,
|
||||
`${siteDomain}/img/social-studies-tutoring.png`
|
||||
]
|
||||
|
||||
// SEO 태그 및 소셜 메타데이터 (더세이브 방식 메타태그 + 3분할 구조화 데이터 JSON-LD)
|
||||
useHead({
|
||||
title: '로열클래스 1:1 과외 | 인천 초·중·고 검증된 맞춤 과외 매칭',
|
||||
title: homeTitle,
|
||||
link: [
|
||||
{ rel: 'canonical', href: 'https://aeseo.site/' }
|
||||
{ rel: 'canonical', href: homeCanonical }
|
||||
],
|
||||
meta: [
|
||||
{ name: 'robots', content: 'index,follow' },
|
||||
{ name: 'naver-site-verification', content: '797ab1ac988eb27c80ae544bb6aba05c2231a9c9' },
|
||||
{ name: 'description', content: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 명문대 및 베테랑 전문 강사진 1:1 맞춤 배정 솔루션' },
|
||||
{ name: 'description', content: homeDesc },
|
||||
{ name: 'keywords', content: '인천 중등 수학 과외, 인천 중등 과외, 인천 고등 수학 과외, 인천 고등 과외, 인천 초등 수학 과외, 인천 초등 과외, 인천 중등 영어 과외, 인천 고등 영어 과외, 인천 과외, 송도동 과외, 송도동 중등 수학 과외' },
|
||||
{ property: 'og:type', content: 'website' },
|
||||
{ property: 'og:site_name', content: '로열클래스 1:1 과외' },
|
||||
{ property: 'og:title', content: '로열클래스 1:1 과외 | 인천 초·중·고 맞춤 과외 매칭' },
|
||||
{ property: 'og:description', content: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 검증된 전문 선생님 100% 매칭' },
|
||||
{ property: 'og:url', content: 'https://aeseo.site/' },
|
||||
{ property: 'og:image', content: 'https://aeseo.site/img/og-main.png' },
|
||||
{ property: 'og:locale', content: 'ko_KR' },
|
||||
{ property: 'og:site_name', content: siteName },
|
||||
{ property: 'og:title', content: homeTitle },
|
||||
{ property: 'og:description', content: homeDesc },
|
||||
{ property: 'og:url', content: homeCanonical },
|
||||
{ property: 'og:image', content: `${siteDomain}/img/og-main.png` },
|
||||
{ property: 'og:image:type', content: 'image/png' },
|
||||
{ property: 'og:image:width', content: '1200' },
|
||||
{ property: 'og:image:height', content: '630' },
|
||||
{ property: 'og:image:alt', content: '인천 중등 수학 과외 · 인천 중등 과외' },
|
||||
{ name: 'twitter:card', content: 'summary_large_image' },
|
||||
{ name: 'twitter:title', content: '로열클래스 1:1 과외 | 인천 초·중·고 맞춤 과외 매칭' },
|
||||
{ name: 'twitter:description', content: '과외 비용·시세 투명 비교부터 무료 시범수업 신청까지. 검증된 전문 선생님 100% 매칭' },
|
||||
{ name: 'twitter:image', content: 'https://aeseo.site/img/og-main.png' }
|
||||
{ name: 'twitter:title', content: homeTitle },
|
||||
{ name: 'twitter:description', content: homeDesc },
|
||||
{ name: 'twitter:image', content: `${siteDomain}/img/og-main.png` }
|
||||
],
|
||||
script: [
|
||||
// 1. EducationalOrganization / LocalBusiness 스키마
|
||||
// 1. @graph (WebSite + WebPage + ImageObject + EducationalOrganization + LocalBusiness)
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': ['EducationalOrganization', 'LocalBusiness'],
|
||||
name: '로열클래스 1:1 과외',
|
||||
telephone: '+82-10-5961-5807',
|
||||
url: 'https://aeseo.site/',
|
||||
image: 'https://aeseo.site/img/og-main.png',
|
||||
address: {
|
||||
'@type': 'PostalAddress',
|
||||
streetAddress: '송도과학로 32 테크노파크 5층',
|
||||
addressLocality: '연수구',
|
||||
addressRegion: '인천광역시',
|
||||
addressCountry: 'KR'
|
||||
},
|
||||
description: '인천 초·중·고 1:1 맞춤 과외 및 방문·화상 시범수업 전문 교육 기관',
|
||||
areaServed: '인천광역시 전지역'
|
||||
'@graph': [
|
||||
{
|
||||
'@type': 'WebSite',
|
||||
'@id': `${siteDomain}/#site`,
|
||||
url: homeCanonical,
|
||||
name: siteName,
|
||||
inLanguage: 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'WebPage',
|
||||
'@id': `${homeCanonical}#page`,
|
||||
url: homeCanonical,
|
||||
name: homeTitle,
|
||||
description: homeDesc,
|
||||
isPartOf: { '@id': `${siteDomain}/#site` },
|
||||
primaryImageOfPage: { '@id': `${homeCanonical}#img` },
|
||||
inLanguage: 'ko-KR'
|
||||
},
|
||||
{
|
||||
'@type': 'ImageObject',
|
||||
'@id': `${homeCanonical}#img`,
|
||||
url: `${siteDomain}/img/math-tutoring.png`,
|
||||
contentUrl: `${siteDomain}/img/math-tutoring.png`,
|
||||
width: 1080,
|
||||
height: 1080,
|
||||
caption: '인천 중등 수학 과외 · 인천 중등 과외'
|
||||
},
|
||||
{
|
||||
'@type': ['EducationalOrganization', 'LocalBusiness'],
|
||||
'@id': `${siteDomain}/#org`,
|
||||
name: siteName,
|
||||
telephone: '+82-10-5961-5807',
|
||||
url: homeCanonical,
|
||||
image: allBrandImages,
|
||||
priceRange: '₩₩',
|
||||
address: {
|
||||
'@type': 'PostalAddress',
|
||||
streetAddress: '송도과학로 32 테크노파크 5층',
|
||||
addressLocality: '연수구',
|
||||
addressRegion: '인천광역시',
|
||||
addressCountry: 'KR'
|
||||
},
|
||||
description: homeDesc,
|
||||
areaServed: '인천광역시 전지역'
|
||||
}
|
||||
]
|
||||
})
|
||||
},
|
||||
// 2. FAQPage 스키마
|
||||
@@ -666,50 +724,57 @@ useHead({
|
||||
}))
|
||||
})
|
||||
},
|
||||
// 3. ItemList 과목별 갤러리 섹션 스키마
|
||||
// 3. ItemList 과목별 및 학년별 서브 라우터 캐러셀 스키마 (최상위 name, url, image + item: Course 바인딩)
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'ItemList',
|
||||
name: '과목별 1:1 맞춤 과외 프로그램',
|
||||
name: '인천 중등 수학 과외 · 인천 중등 과외 및 학년별·과목별 1:1 맞춤 과외 프로그램',
|
||||
itemListElement: [
|
||||
{
|
||||
{ sub: '수학', grade: '중학생', title: '인천 중등 수학 과외 · 중학생 수학과외', desc: '인천 중등 수학 과외 및 인천 중등 과외 개념 구멍 추적 및 킬러 문항 1:1 완파', img: 'math-tutoring.png' },
|
||||
{ sub: '영어', grade: '중학생', title: '인천 중등 영어 과외 · 중학생 영어과외', desc: '인천 중등 영어 과외 및 인천 중등 과외 교과서·부교재 전 지문 변형 및 서술형 영작', img: 'english-tutoring.png' },
|
||||
{ sub: '국어', grade: '중학생', title: '인천 중등 국어 과외 · 중학생 국어과외', desc: '인천 중등 국어 과외 및 비문학 독해 논리와 교과서 문학 1:1 정밀 분석', img: 'korean-tutoring.png' },
|
||||
{ sub: '과학', grade: '중학생', title: '인천 중등 과학 과외 · 중학생 과학과외', desc: '인천 중등 과학 과외 및 통합과학 원리 이해·물화생지 킬러 단원 정복', img: 'science-tutoring.png' },
|
||||
{ sub: '사회', grade: '중학생', title: '인천 중등 사회 과외 · 중학생 사회과외', desc: '인천 중등 사회 과외 및 통합사회·한국사 핵심 흐름 만점 전략', img: 'social-studies-tutoring.png' },
|
||||
{ sub: '수학', grade: '초등학생', title: '인천 초등 수학 과외 · 초등학생 수학과외', desc: '인천 초등 수학 과외 기초 연산 습관 형성 및 중등 선행 심화 대비', img: 'math-tutoring.png' },
|
||||
{ sub: '영어', grade: '고등학생', title: '인천 고등 영어 과외 · 고등학생 영어과외', desc: '인천 고등 영어 과외 내신 서술형 감점 방지 및 수능 1등급 완성', img: 'english-tutoring.png' },
|
||||
{ sub: '수학', grade: '고등학생', title: '인천 고등 수학 과외 · 고등학생 수학과외', desc: '인천 고등 수학 과외 공통수학·미적분 킬러 문항 및 내신 1등급 전략', img: 'math-tutoring.png' }
|
||||
].map((item, idx) => {
|
||||
const courseUrl = `${siteDomain}/${encodeURIComponent(defaultDong)}/${encodeURIComponent(item.grade)}/${encodeURIComponent(item.sub)}`
|
||||
const courseImg = `${siteDomain}/img/${item.img}`
|
||||
const courseName = `${item.title} (${defaultDong})`
|
||||
return {
|
||||
'@type': 'ListItem',
|
||||
position: 1,
|
||||
name: '수학과외',
|
||||
description: '개념 구멍 추적 및 킬러 문항 1:1 완파',
|
||||
image: 'https://aeseo.site/img/math-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 2,
|
||||
name: '영어과외',
|
||||
description: '교과서·부교재 전 지문 변형 및 서술형 영작',
|
||||
image: 'https://aeseo.site/img/english-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 3,
|
||||
name: '국어과외',
|
||||
description: '비문학 독해 논리와 교과서 문학 1:1 정밀 분석',
|
||||
image: 'https://aeseo.site/img/korean-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 4,
|
||||
name: '과학과외',
|
||||
description: '통합과학 원리 이해 및 물화생지 킬러 단원 정복',
|
||||
image: 'https://aeseo.site/img/science-tutoring.png'
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 5,
|
||||
name: '사회과외',
|
||||
description: '통합사회·한국사 핵심 흐름 및 사탐 만점 전략',
|
||||
image: 'https://aeseo.site/img/social-studies-tutoring.png'
|
||||
position: idx + 1,
|
||||
name: courseName,
|
||||
url: courseUrl,
|
||||
image: courseImg,
|
||||
item: {
|
||||
'@type': 'Course',
|
||||
name: courseName,
|
||||
description: item.desc,
|
||||
url: courseUrl,
|
||||
image: courseImg,
|
||||
provider: {
|
||||
'@type': 'Organization',
|
||||
name: siteName,
|
||||
sameAs: siteDomain
|
||||
},
|
||||
offers: {
|
||||
'@type': 'Offer',
|
||||
category: 'Paid',
|
||||
priceCurrency: 'KRW',
|
||||
availability: 'https://schema.org/InStock',
|
||||
url: courseUrl
|
||||
},
|
||||
hasCourseInstance: {
|
||||
'@type': 'CourseInstance',
|
||||
courseMode: ['onsite', 'online']
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
</defs>
|
||||
<rect width="1200" height="630" fill="url(#bg)"/>
|
||||
<rect x="80" y="80" width="160" height="48" rx="8" fill="#fbbf24"/>
|
||||
<text x="160" y="112" font-family="'Pretendard', sans-serif" font-size="22" font-weight="900" fill="#1e293b" text-anchor="middle">AESEO</text>
|
||||
<text x="160" y="112" font-family="'Pretendard', sans-serif" font-size="22" font-weight="900" fill="#1e293b" text-anchor="middle">튜터온</text>
|
||||
<text x="80" y="240" font-family="'Pretendard', sans-serif" font-size="56" font-weight="900" fill="#ffffff">우리 동네 초·중·고 1:1 맞춤 과외</text>
|
||||
<text x="80" y="320" font-family="'Pretendard', sans-serif" font-size="68" font-weight="900" fill="#fbbf24">내신 1등급 전문 과외애서</text>
|
||||
<text x="80" y="320" font-family="'Pretendard', sans-serif" font-size="68" font-weight="900" fill="#fbbf24">내신 1등급 전문 튜터온</text>
|
||||
<text x="80" y="420" font-family="'Pretendard', sans-serif" font-size="30" font-weight="500" fill="#e0e7ff">국어 · 영어 · 수학 · 과학 · 사회 · 수행평가 세특</text>
|
||||
<text x="80" y="480" font-family="'Pretendard', sans-serif" font-size="28" font-weight="700" fill="#ffffff">전국 568개 동 학교별 기출 족보 완벽 분석</text>
|
||||
<rect x="80" y="530" width="340" height="50" rx="25" fill="#10b981"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -83,7 +83,7 @@
|
||||
|
||||
<!-- 성적 상승 그래프 비주얼 -->
|
||||
<text x="35" y="55" fill="#f8fafc" font-size="18" font-weight="800" font-family="'Pretendard', sans-serif">
|
||||
AESEO 성적 향상 지표
|
||||
튜터온 성적 향상 지표
|
||||
</text>
|
||||
<text x="35" y="80" fill="#94a3b8" font-size="13" font-family="'Pretendard', sans-serif">
|
||||
수강생 평균 2.3등급 수직 상승
|
||||
@@ -96,7 +96,7 @@
|
||||
<text x="32" y="55" fill="#94a3b8" font-size="13" font-weight="700" text-anchor="middle">4등급</text>
|
||||
<text x="32" y="185" fill="#94a3b8" font-size="12" text-anchor="middle">수강 전</text>
|
||||
|
||||
<!-- 과외애서 수강 후 바 -->
|
||||
<!-- 튜터온 수강 후 바 -->
|
||||
<rect x="95" y="10" width="75" height="150" rx="6" fill="url(#goldGrad)" />
|
||||
<text x="132" y="-5" fill="#f59e0b" font-size="16" font-weight="900" text-anchor="middle">1등급!</text>
|
||||
<text x="132" y="185" fill="#ffffff" font-size="13" font-weight="800" text-anchor="middle">수강 3개월</text>
|
||||
@@ -118,7 +118,7 @@
|
||||
|
||||
<!-- 우측 하단 워터마크 -->
|
||||
<text x="355" y="325" fill="#ffffff" opacity="0.3" font-size="13" font-weight="800" text-anchor="end" font-family="'Pretendard', sans-serif">
|
||||
AESEO TUTORING POSTER
|
||||
튜터온 TUTORING POSTER
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.2 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.3 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.3 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.3 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.3 MiB |
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.3 MiB |