feat(ui): update hero button text and enhance welcome screen
- Change primary hero button text from "Start Learning" to "Start Vibe Together!" across all language versions to align with project branding - Update online reading links in README files to point to /welcome.html for better user onboarding - Enhance WelcomeScreen.vue with improved animation timing and spacing - Add dynamic SVG wordmark to homepage hero section for visual appeal - Implement animated color transition for top promo bar - Remove testing guidelines comment in AGENTS.md as placeholder - Adjust feature card styling with increased min-height and icon sizes
This commit is contained in:
@@ -6,6 +6,7 @@ import GitHubStars from './components/GitHubStars.vue'
|
||||
import { onMounted, ref, watch, computed } from 'vue'
|
||||
import ReadingProgress from './components/ReadingProgress.vue'
|
||||
import { Setting } from '@element-plus/icons-vue'
|
||||
import easyVibePaths from './data/easyVibePaths.json'
|
||||
|
||||
const { frontmatter } = useData()
|
||||
const route = useRoute()
|
||||
@@ -416,6 +417,38 @@ watch(sidebarCollapsed, (collapsed) => {
|
||||
</el-popover>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
<template #home-hero-info-before>
|
||||
<div
|
||||
v-if="frontmatter.layout === 'home'"
|
||||
class="vp-home-wordmark"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 460 220"
|
||||
class="vp-home-wordmark-svg"
|
||||
>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="home-hero-ocean"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="460"
|
||||
y2="0"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0%" stop-color="#06b6d4" />
|
||||
<stop offset="50%" stop-color="#0ea5e9" />
|
||||
<stop offset="100%" stop-color="#3b82f6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path
|
||||
v-for="(path, index) in easyVibePaths"
|
||||
:key="index"
|
||||
:d="path"
|
||||
class="vp-home-wordmark-path"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
<template #home-hero-info-after>
|
||||
<div
|
||||
v-if="
|
||||
@@ -467,7 +500,8 @@ watch(sidebarCollapsed, (collapsed) => {
|
||||
|
||||
/* 调整打字机容器的样式,使其看起来像原来的 tagline */
|
||||
.vp-typed-tagline {
|
||||
padding-top: 8px;
|
||||
padding-top: 0;
|
||||
margin-top: 8px;
|
||||
line-height: 28px;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
@@ -485,7 +519,7 @@ watch(sidebarCollapsed, (collapsed) => {
|
||||
text-align: center;
|
||||
}
|
||||
.VPHomeHero .main {
|
||||
margin: 0 auto;
|
||||
margin: -18px auto 0;
|
||||
}
|
||||
.VPHomeHero .name,
|
||||
.VPHomeHero .text {
|
||||
@@ -493,11 +527,30 @@ watch(sidebarCollapsed, (collapsed) => {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.VPHomeHero .name {
|
||||
display: none !important;
|
||||
}
|
||||
.VPHomeHero .text {
|
||||
color: var(--vp-c-text-1) !important;
|
||||
}
|
||||
.VPHomeHero .actions {
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.vp-home-wordmark {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: -12px;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
.vp-home-wordmark-svg {
|
||||
width: min(380px, 52vw);
|
||||
height: auto;
|
||||
filter: none;
|
||||
}
|
||||
.vp-home-wordmark-path {
|
||||
fill: url(#home-hero-ocean);
|
||||
stroke: none;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
|
||||
@@ -8,6 +8,11 @@ const { site, page, lang } = useData()
|
||||
const activeTab = ref('home')
|
||||
const showLangMenu = ref(false)
|
||||
const topPromoProgress = ref(1)
|
||||
const topPromoIntroProgress = ref(0)
|
||||
const topPromoColorProgress = ref(0)
|
||||
let topPromoIntroRaf = 0
|
||||
let topPromoColorRaf = 0
|
||||
let topPromoColorTimer = 0
|
||||
const WELCOME_SEEN_KEY = 'easy-vibe-welcome-seen'
|
||||
|
||||
// Appendix Scroll Logic
|
||||
@@ -1620,12 +1625,27 @@ const updateTopPromoVisibility = () => {
|
||||
}
|
||||
|
||||
const topPromoStyle = computed(() => {
|
||||
const progress = topPromoProgress.value
|
||||
const scrollProgress = topPromoProgress.value
|
||||
const introProgress = topPromoIntroProgress.value
|
||||
const colorProgress = topPromoColorProgress.value
|
||||
const progress = scrollProgress * introProgress
|
||||
const scrollOffset = -100 * (1 - scrollProgress)
|
||||
const startTextColor = { r: 255, g: 255, b: 255 }
|
||||
const endTextColor = { r: 29, g: 29, b: 31 }
|
||||
const startBgColor = { r: 0, g: 113, b: 227 }
|
||||
const endBgColor = { r: 245, g: 245, b: 247 }
|
||||
const startLinkColor = { r: 255, g: 255, b: 255 }
|
||||
const endLinkColor = { r: 0, g: 102, b: 204 }
|
||||
const textColor = `rgb(${Math.round(startTextColor.r + (endTextColor.r - startTextColor.r) * colorProgress)}, ${Math.round(startTextColor.g + (endTextColor.g - startTextColor.g) * colorProgress)}, ${Math.round(startTextColor.b + (endTextColor.b - startTextColor.b) * colorProgress)})`
|
||||
const bgColor = `rgb(${Math.round(startBgColor.r + (endBgColor.r - startBgColor.r) * colorProgress)}, ${Math.round(startBgColor.g + (endBgColor.g - startBgColor.g) * colorProgress)}, ${Math.round(startBgColor.b + (endBgColor.b - startBgColor.b) * colorProgress)})`
|
||||
const linkColor = `rgb(${Math.round(startLinkColor.r + (endLinkColor.r - startLinkColor.r) * colorProgress)}, ${Math.round(startLinkColor.g + (endLinkColor.g - startLinkColor.g) * colorProgress)}, ${Math.round(startLinkColor.b + (endLinkColor.b - startLinkColor.b) * colorProgress)})`
|
||||
return {
|
||||
opacity: progress,
|
||||
transform: `translateY(${-100 * (1 - progress)}%)`,
|
||||
transform: `translateY(${scrollOffset}%)`,
|
||||
maxHeight: `${30 * progress}px`,
|
||||
borderTopColor: `rgba(229, 229, 234, ${progress})`,
|
||||
backgroundColor: bgColor,
|
||||
color: textColor,
|
||||
'--top-promo-link-color': linkColor,
|
||||
pointerEvents: progress < 0.02 ? 'none' : 'auto'
|
||||
}
|
||||
})
|
||||
@@ -1636,6 +1656,33 @@ const replayIntro = () => {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const introDuration = 1800
|
||||
const colorDelay = 500
|
||||
const colorDuration = 1800
|
||||
const introStart = performance.now()
|
||||
const stepTopPromoIntro = (now) => {
|
||||
const raw = Math.min(1, (now - introStart) / introDuration)
|
||||
const eased = 1 - Math.pow(1 - raw, 3)
|
||||
topPromoIntroProgress.value = eased
|
||||
if (raw < 1) {
|
||||
topPromoIntroRaf = window.requestAnimationFrame(stepTopPromoIntro)
|
||||
return
|
||||
}
|
||||
topPromoColorTimer = window.setTimeout(() => {
|
||||
const colorStart = performance.now()
|
||||
const stepTopPromoColor = (time) => {
|
||||
const colorRaw = Math.min(1, (time - colorStart) / colorDuration)
|
||||
const colorEased = 1 - Math.pow(1 - colorRaw, 3)
|
||||
topPromoColorProgress.value = colorEased
|
||||
if (colorRaw < 1) {
|
||||
topPromoColorRaf = window.requestAnimationFrame(stepTopPromoColor)
|
||||
}
|
||||
}
|
||||
topPromoColorRaf = window.requestAnimationFrame(stepTopPromoColor)
|
||||
}, colorDelay)
|
||||
}
|
||||
topPromoIntroRaf = window.requestAnimationFrame(stepTopPromoIntro)
|
||||
|
||||
const currentPath = window.location.pathname
|
||||
const basePath = site.value.base || '/'
|
||||
const normalizedBase = basePath.endsWith('/') ? basePath : `${basePath}/`
|
||||
@@ -1681,6 +1728,18 @@ onMounted(() => {
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (topPromoIntroRaf) {
|
||||
window.cancelAnimationFrame(topPromoIntroRaf)
|
||||
topPromoIntroRaf = 0
|
||||
}
|
||||
if (topPromoColorRaf) {
|
||||
window.cancelAnimationFrame(topPromoColorRaf)
|
||||
topPromoColorRaf = 0
|
||||
}
|
||||
if (topPromoColorTimer) {
|
||||
window.clearTimeout(topPromoColorTimer)
|
||||
topPromoColorTimer = 0
|
||||
}
|
||||
document.removeEventListener('click', closeLangMenu)
|
||||
if (appendixWrapper.value) {
|
||||
appendixWrapper.value.removeEventListener('scroll', onAppendixScroll)
|
||||
@@ -2365,8 +2424,8 @@ a {
|
||||
}
|
||||
|
||||
.nav-promo {
|
||||
height: 30px;
|
||||
max-height: 30px;
|
||||
border-top: 1px solid #e5e5ea;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -2378,17 +2437,19 @@ a {
|
||||
transform-origin: top center;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
will-change: transform, opacity, max-height, border-color;
|
||||
will-change: transform, opacity, max-height, background-color, color;
|
||||
transition:
|
||||
transform 0.16s ease-out,
|
||||
opacity 0.16s ease-out,
|
||||
max-height 0.16s ease-out,
|
||||
border-color 0.16s ease-out;
|
||||
background-color 0.22s ease-out,
|
||||
color 0.22s ease-out;
|
||||
}
|
||||
|
||||
.nav-promo a {
|
||||
color: #0066cc;
|
||||
color: var(--top-promo-link-color, #0066cc);
|
||||
text-decoration: none;
|
||||
transition: color 0.25s ease-out;
|
||||
}
|
||||
|
||||
.button {
|
||||
@@ -2786,6 +2847,7 @@ a {
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.04);
|
||||
scroll-snap-align: start;
|
||||
width: 100%;
|
||||
min-height: 360px;
|
||||
transition: transform 0.25s ease;
|
||||
}
|
||||
|
||||
@@ -2853,14 +2915,14 @@ a {
|
||||
}
|
||||
|
||||
.appendix-icon-wrapper {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 17.5px; /* Apple continuous curve approximation */
|
||||
width: 100%;
|
||||
height: 190px;
|
||||
border-radius: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32px;
|
||||
margin-bottom: 16px;
|
||||
font-size: 88px;
|
||||
margin-bottom: 14px;
|
||||
/* Glassmorphism / VisionOS Style */
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
@@ -2916,7 +2978,7 @@ a {
|
||||
}
|
||||
|
||||
.appendix-text {
|
||||
font-size: 15px;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
color: #6e6e73;
|
||||
margin: 0;
|
||||
@@ -2928,7 +2990,7 @@ a {
|
||||
font-weight: 600;
|
||||
color: #1d1d1f;
|
||||
margin-right: 6px;
|
||||
font-size: 13px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
|
||||
@@ -258,23 +258,26 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.welcome-tip {
|
||||
margin: 24px 0 0;
|
||||
margin: 44px 0 0;
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.08em;
|
||||
color: rgba(34, 34, 34, 0.38);
|
||||
letter-spacing: 0.2em;
|
||||
color: rgba(34, 34, 34, 0.32);
|
||||
text-transform: uppercase;
|
||||
animation: welcome-tip-breathe 7s ease-in-out infinite;
|
||||
animation: welcome-tip-breathe 5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes welcome-tip-breathe {
|
||||
0% {
|
||||
opacity: 0.24;
|
||||
opacity: 0;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.72;
|
||||
40% {
|
||||
opacity: 0.55;
|
||||
}
|
||||
80% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 0.24;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -305,15 +305,43 @@
|
||||
}
|
||||
|
||||
/* Hero Section Refinements */
|
||||
.VPHomeHero .name {
|
||||
background: -webkit-linear-gradient(315deg, #0071e3 10%, #5ac8fa 90%);
|
||||
.VPHomeHero .name,
|
||||
.VPHomeHero .name.clip {
|
||||
position: relative;
|
||||
top: -8px;
|
||||
background-image: linear-gradient(
|
||||
100deg,
|
||||
#06b6d4 0%,
|
||||
#0ea5e9 18%,
|
||||
#3b82f6 36%,
|
||||
#9d4edd 56%,
|
||||
#ff3c81 74%,
|
||||
#f97316 88%,
|
||||
#06b6d4 100%
|
||||
);
|
||||
background-size: 220% 220%;
|
||||
background-position: 0% 50%;
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
filter: drop-shadow(0 0 24px rgba(0, 113, 227, 0.28));
|
||||
filter: drop-shadow(0 0 22px rgba(59, 130, 246, 0.26));
|
||||
animation: ev-hero-name-flow 8s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes ev-hero-name-flow {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 35% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.VPHomeHero .text {
|
||||
display: none !important;
|
||||
font-weight: 600;
|
||||
color: #1d1d1f;
|
||||
letter-spacing: -0.02em;
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ hero:
|
||||
- هكذا يجب أن تكون البرمجة.
|
||||
actions:
|
||||
- theme: brand
|
||||
text: ابدأ التعلم
|
||||
text: ابدأ vibe معًا!
|
||||
link: /ar-sa/stage-0/
|
||||
- theme: alt
|
||||
text: مخطط الدورة
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ hero:
|
||||
- So sollte Programmieren sich anfühlen.
|
||||
actions:
|
||||
- theme: brand
|
||||
text: Starten
|
||||
text: Zusammen vibe starten!
|
||||
link: /de-de/stage-0/
|
||||
- theme: alt
|
||||
text: Kursübersicht
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ hero:
|
||||
- This is how coding should feel.
|
||||
actions:
|
||||
- theme: brand
|
||||
text: Start Learning
|
||||
text: Start Vibe Together!
|
||||
link: /en/stage-0/
|
||||
- theme: alt
|
||||
text: GitHub
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ hero:
|
||||
- Así debería sentirse programar.
|
||||
actions:
|
||||
- theme: brand
|
||||
text: Empezar
|
||||
text: ¡Empezar a vibe juntos!
|
||||
link: /es-es/stage-0/
|
||||
- theme: alt
|
||||
text: Esquema del Curso
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ hero:
|
||||
- C'est ainsi que le coding devrait être.
|
||||
actions:
|
||||
- theme: brand
|
||||
text: Commencer
|
||||
text: Commencer à vibe ensemble !
|
||||
link: /fr-fr/stage-0/
|
||||
- theme: alt
|
||||
text: Plan du Cours
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ hero:
|
||||
- プログラミングは、こうあるべき。
|
||||
actions:
|
||||
- theme: brand
|
||||
text: 学習を開始
|
||||
text: 一緒にvibeを始めよう!
|
||||
link: /ja-jp/stage-0/
|
||||
- theme: alt
|
||||
text: コース概要
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ hero:
|
||||
- 프로그래밍은, 이래야 합니다.
|
||||
actions:
|
||||
- theme: brand
|
||||
text: 학습 시작
|
||||
text: 함께 vibe 시작!
|
||||
link: /ko-kr/stage-0/
|
||||
- theme: alt
|
||||
text: 과정 개요
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ hero:
|
||||
- Lập trình nên như thế này.
|
||||
actions:
|
||||
- theme: brand
|
||||
text: Bắt đầu học
|
||||
text: Bắt đầu vibe cùng nhau!
|
||||
link: /vi-vn/stage-0/
|
||||
- theme: alt
|
||||
text: Đề cương khóa học
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ hero:
|
||||
- 这就是编程该有的样子。
|
||||
actions:
|
||||
- theme: brand
|
||||
text: 开始学习
|
||||
text: 开始一起 vibe!
|
||||
link: /zh-cn/stage-0/0.1-learning-map/
|
||||
- theme: alt
|
||||
text: GitHub 加速更新
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ hero:
|
||||
- 這就是編程該有的樣子。
|
||||
actions:
|
||||
- theme: brand
|
||||
text: 開始學習
|
||||
text: 開始一起 vibe!
|
||||
link: /zh-tw/stage-0/
|
||||
- theme: alt
|
||||
text: 課程大綱
|
||||
|
||||
Reference in New Issue
Block a user