Skip to content

Commit c0d0c5b

Browse files
committed
2 parents a18141d + b887390 commit c0d0c5b

7 files changed

Lines changed: 222 additions & 17 deletions

File tree

.vitepress/config.mts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,21 @@ export default defineConfig({
2121
srcExclude,
2222
cleanUrls: true,
2323
lastUpdated: true,
24+
vite: {
25+
css: {
26+
postcss: {
27+
plugins: []
28+
}
29+
}
30+
},
2431
ignoreDeadLinks: [/^https?:\/\//],
2532
head: [
2633
['link', { rel: 'icon', href: '/brand/notionnext-logo.png', type: 'image/png' }],
2734
['link', { rel: 'apple-touch-icon', href: '/brand/notionnext-logo.png' }]
2835
],
36+
transformHtml(html) {
37+
return html.replace(/rel="preload stylesheet"/g, 'rel="stylesheet"')
38+
},
2939
themeConfig: {
3040
logo: '/brand/notionnext-logo.png',
3141
nav: [

.vitepress/theme/Layout.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
<script setup lang="ts">
22
import DefaultTheme from 'vitepress/theme'
33
import GiscusComment from './components/GiscusComment.vue'
4+
import HomeMotion from './components/HomeMotion.vue'
45
56
const { Layout } = DefaultTheme
67
</script>
78

89
<template>
910
<Layout>
11+
<template #layout-bottom>
12+
<ClientOnly>
13+
<HomeMotion />
14+
</ClientOnly>
15+
</template>
1016
<template #doc-footer-before>
1117
<GiscusComment />
1218
</template>
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<script setup lang="ts">
2+
import { nextTick, onBeforeUnmount, onMounted, watch } from 'vue'
3+
import { useRoute } from 'vitepress'
4+
5+
const route = useRoute()
6+
7+
let teardown: (() => void) | undefined
8+
9+
function isHomeRoute() {
10+
return route.path === '/' || route.path === '/index.html'
11+
}
12+
13+
async function resetMotion() {
14+
teardown?.()
15+
teardown = undefined
16+
17+
if (!isHomeRoute() || typeof window === 'undefined') {
18+
return
19+
}
20+
21+
await nextTick()
22+
await new Promise((resolve) => window.requestAnimationFrame(() => resolve(undefined)))
23+
24+
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
25+
if (reduceMotion) {
26+
return
27+
}
28+
29+
const [{ gsap }, { ScrollTrigger }] = await Promise.all([
30+
import('gsap'),
31+
import('gsap/ScrollTrigger')
32+
])
33+
34+
gsap.registerPlugin(ScrollTrigger)
35+
36+
const ctx = gsap.context(() => {
37+
const heroTargets = [
38+
'.VPHomeHero .name',
39+
'.VPHomeHero .text',
40+
'.VPHomeHero .tagline',
41+
'.VPHomeHero .actions',
42+
'.VPHomeHero .image'
43+
].filter((selector) => document.querySelector(selector))
44+
45+
gsap
46+
.timeline({ defaults: { ease: 'power3.out' } })
47+
.from(heroTargets, {
48+
autoAlpha: 0,
49+
y: 24,
50+
duration: 0.72,
51+
stagger: 0.08,
52+
clearProps: 'transform,visibility,opacity'
53+
})
54+
.from(
55+
'.VPHome .VPFeature',
56+
{
57+
autoAlpha: 0,
58+
y: 18,
59+
duration: 0.52,
60+
stagger: 0.05,
61+
clearProps: 'transform,visibility,opacity'
62+
},
63+
'-=0.28'
64+
)
65+
66+
gsap.utils.toArray('.nn-home-section').forEach((section, sectionIndex) => {
67+
const homeSection = section as HTMLElement
68+
const sectionTargets = homeSection.querySelectorAll(
69+
'.nn-home-kicker, h2, .nn-section-heading > a, .nn-compare-card, .nn-step-card, .nn-theme-card, .nn-usecase-grid > a, .nn-open-grid > div, .nn-faq-list details'
70+
)
71+
72+
gsap.from(sectionTargets.length ? sectionTargets : homeSection, {
73+
autoAlpha: 0,
74+
y: 30,
75+
duration: 0.62,
76+
ease: 'power3.out',
77+
stagger: 0.055,
78+
clearProps: 'transform,visibility,opacity',
79+
scrollTrigger: {
80+
trigger: homeSection,
81+
start: 'top 82%',
82+
once: true,
83+
refreshPriority: sectionIndex
84+
}
85+
})
86+
})
87+
88+
ScrollTrigger.refresh()
89+
}, document.body)
90+
91+
teardown = () => {
92+
ctx.revert()
93+
}
94+
}
95+
96+
onMounted(() => {
97+
resetMotion()
98+
})
99+
100+
watch(
101+
() => route.path,
102+
() => {
103+
resetMotion()
104+
}
105+
)
106+
107+
onBeforeUnmount(() => {
108+
teardown?.()
109+
})
110+
</script>
111+
112+
<template></template>

.vitepress/theme/style.css

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,25 @@
8080
background: var(--vp-c-bg-soft);
8181
}
8282

83+
.VPHome .VPHomeHero .name,
84+
.VPHome .VPHomeHero .text,
85+
.VPHome .VPHomeHero .tagline,
86+
.VPHome .VPHomeHero .actions,
87+
.VPHome .VPHomeHero .image,
88+
.VPHome .VPFeature,
89+
.nn-home-section,
90+
.nn-home-section .nn-home-kicker,
91+
.nn-home-section h2,
92+
.nn-section-heading > a,
93+
.nn-compare-card,
94+
.nn-step-card,
95+
.nn-theme-card,
96+
.nn-usecase-grid > a,
97+
.nn-open-grid > div,
98+
.nn-faq-list details {
99+
will-change: transform, opacity;
100+
}
101+
83102
.nn-compare-card {
84103
min-height: 220px;
85104
padding: 24px;
@@ -130,6 +149,20 @@
130149
transform: translateY(-2px);
131150
}
132151

152+
@media (prefers-reduced-motion: reduce) {
153+
.nn-step-card,
154+
.nn-usecase-grid > a,
155+
.nn-theme-card {
156+
transition: none;
157+
}
158+
159+
.nn-step-card:hover,
160+
.nn-usecase-grid > a:hover,
161+
.nn-theme-card:hover {
162+
transform: none;
163+
}
164+
}
165+
133166
.nn-step-card span {
134167
display: inline-flex;
135168
align-items: center;
@@ -253,29 +286,67 @@
253286
.VPHome .VPHomeHero .text,
254287
.VPHome .VPHomeHero .tagline {
255288
max-width: 100%;
289+
overflow-wrap: anywhere;
290+
word-break: break-all;
291+
}
292+
293+
.VPHome .VPHomeHero .container {
294+
box-sizing: border-box;
295+
padding-inline: 24px;
296+
}
297+
298+
.VPHome .VPHomeHero .text {
299+
width: 100%;
300+
max-width: 280px;
301+
margin-inline: auto;
302+
font-size: 28px;
303+
line-height: 1.18;
304+
white-space: normal;
305+
}
306+
307+
.VPHome .VPHomeHero .tagline {
308+
max-width: 280px;
309+
margin-inline: auto;
310+
font-size: 18px;
311+
line-height: 1.7;
312+
white-space: normal;
256313
}
257314

258315
.VPHome .VPHomeHero .actions {
259-
flex-wrap: wrap;
260-
justify-content: center;
316+
display: grid;
317+
grid-template-columns: 1fr;
318+
width: min(100%, 280px);
319+
margin-inline: auto;
261320
}
262321

263322
.VPHome .VPHomeHero .action {
264323
min-width: 0;
265324
}
266325

267326
.VPHome .VPHomeHero .VPButton {
327+
width: 100%;
268328
max-width: 100%;
269329
white-space: normal;
270330
}
271331

272332
.VPHome .VPFeatures .items {
273333
grid-template-columns: 1fr !important;
334+
max-width: 100%;
274335
}
275336

276337
.VPHome .VPFeature {
338+
box-sizing: border-box;
339+
width: 100%;
277340
min-width: 0;
278341
overflow-wrap: anywhere;
342+
word-break: break-all;
343+
}
344+
345+
.VPHome .VPFeature .title,
346+
.VPHome .VPFeature .details {
347+
max-width: 280px;
348+
overflow-wrap: anywhere;
349+
word-break: break-all;
279350
}
280351

281352
.nn-home-section {

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
"axios": "^1.16.1",
7979
"critters": "^0.0.23",
8080
"feed": "^4.2.2",
81+
"gsap": "^3.15.0",
8182
"ioredis": "^5.10.1",
8283
"js-md5": "^0.8.3",
8384
"js-sha256": "^0.11.1",

themes/theme.js

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ const getLayoutLoading = (themeName, layoutName) => {
4444
if (themeName === 'magzine' && layoutName === 'LayoutIndex') {
4545
return MagzineLayoutLoading
4646
}
47-
return undefined
4847
}
4948

5049
const normalizeThemeName = themeValue => {
@@ -164,20 +163,21 @@ export const useLayoutByTheme = ({ layoutName, theme }) => {
164163
return layoutByThemeCache.get(cacheKey)
165164
}
166165

167-
const DynamicLayoutComponent = dynamic(
168-
() =>
169-
import(`@/themes/${themeQuery}`).then(componentsSource => {
170-
const Selected =
171-
componentsSource[layoutName] || componentsSource.LayoutSlug
172-
if (!Selected) {
173-
throw new Error(
174-
`[theme] Layout "${layoutName}" missing in themes/${themeQuery}`
175-
)
176-
}
177-
return Selected
178-
}),
179-
{ ssr: true, loading: getLayoutLoading(themeQuery, layoutName) }
180-
)
166+
const loadLayout = () =>
167+
import(`@/themes/${themeQuery}`).then(componentsSource => {
168+
const Selected =
169+
componentsSource[layoutName] || componentsSource.LayoutSlug
170+
if (!Selected) {
171+
throw new Error(
172+
`[theme] Layout "${layoutName}" missing in themes/${themeQuery}`
173+
)
174+
}
175+
return Selected
176+
})
177+
const layoutLoading = getLayoutLoading(themeQuery, layoutName)
178+
const DynamicLayoutComponent = layoutLoading
179+
? dynamic(loadLayout, { ssr: true, loading: layoutLoading })
180+
: dynamic(loadLayout, { ssr: true })
181181
layoutByThemeCache.set(cacheKey, DynamicLayoutComponent)
182182
scheduleFixThemeDOM(themeQuery === BLOG.THEME ? 80 : 240)
183183
return DynamicLayoutComponent

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4974,6 +4974,11 @@ graphemer@^1.4.0:
49744974
resolved "https://registry.npmmirror.com/graphemer/-/graphemer-1.4.0.tgz"
49754975
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
49764976

4977+
gsap@^3.15.0:
4978+
version "3.15.0"
4979+
resolved "https://registry.npmmirror.com/gsap/-/gsap-3.15.0.tgz"
4980+
integrity sha512-dMW4CWBTUK1AEEDeZc1g4xpPGIrSf9fJF960qbTZmN/QwZIWY5wgliS6JWl9/25fpTGJrMRtSjGtOmPnfjZB+A==
4981+
49774982
gzip-size@^6.0.0:
49784983
version "6.0.0"
49794984
resolved "https://registry.npmmirror.com/gzip-size/-/gzip-size-6.0.0.tgz"

0 commit comments

Comments
 (0)