feat(docs): refined frontier design with glassmorphism design

This commit is contained in:
khtsly 2026-02-12 00:53:52 +07:00
parent 27e81f811c
commit 5075ea7304
4 changed files with 276 additions and 49 deletions

View file

@ -0,0 +1,165 @@
<template>
<div class="hero-container">
<h1 v-if="staticTitle" class="hero-title">
{{ staticTitle }}
</h1>
<div class="typewriter-wrapper">
<p class="typewriter-text" aria-label="Animated hero text">
{{ displayedText }}<span class="cursor">|</span>
</p>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
const props = withDefaults(defineProps<{
staticTitle?: string
words?: string[]
typeSpeed?: number
deleteSpeed?: number
delay?: number
}>(), {
staticTitle: 'Warp',
words: () => [
'A fast networking library.',
'A simple networking library.',
'A powerful networking library.',
'A lightweight networking',
],
typeSpeed: 50,
deleteSpeed: 20,
delay: 2000
})
const displayedText = ref('')
const currentWordIndex = ref(0)
const isDeleting = ref(false)
let typingTimeout: any = null
const typeLoop = () => {
const currentWord = props.words[currentWordIndex.value]
let currentSpeed = props.typeSpeed
if (isDeleting.value) {
displayedText.value = currentWord.substring(0, displayedText.value.length - 1)
currentSpeed = props.deleteSpeed
} else {
displayedText.value = currentWord.substring(0, displayedText.value.length + 1)
currentSpeed = props.typeSpeed
}
if (!isDeleting.value && displayedText.value === currentWord) {
currentSpeed = props.delay
isDeleting.value = true
} else if (isDeleting.value && displayedText.value === '') {
isDeleting.value = false
currentWordIndex.value = (currentWordIndex.value + 1) % props.words.length
currentSpeed = 500
}
typingTimeout = setTimeout(typeLoop, currentSpeed)
}
onMounted(() => {
typeLoop()
})
onUnmounted(() => {
clearTimeout(typingTimeout)
})
</script>
<style scoped>
.hero-container {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
width: 100%;
padding-bottom: 32px;
}
.hero-title {
margin: 0;
padding: 0;
font-weight: 800;
font-size: 75px;
line-height: 1;
letter-spacing: -1.5px;
background: -webkit-linear-gradient(120deg, #fe5234 30%, #fe9934);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0 0 40px rgba(254,82,52,.3);
margin-bottom: 16px;
}
.typewriter-wrapper {
display: flex;
min-height: 120px;
align-items: flex-start;
}
.typewriter-text {
margin: 0;
border: none;
padding: 0;
font-weight: 700;
font-size: 48px;
line-height: 1.2;
letter-spacing: -0.5px;
color: var(--vp-c-text-1);
max-width: 800px;
white-space: pre-wrap;
text-align: left;
}
.cursor {
display: inline-block;
margin-left: 4px;
width: 4px;
height: 1em;
background-color: var(--vp-c-brand-1);
animation: blink 1s step-end infinite;
vertical-align: text-bottom;
}
@keyframes blink {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}
@media (max-width: 960px) {
.hero-title {
font-size: 64px;
}
.typewriter-text {
font-size: 40px;
}
}
@media (max-width: 640px) {
.hero-container {
align-items: center;
text-align: center;
}
.typewriter-text {
text-align: center;
font-size: 32px;
}
.hero-title {
font-size: 48px;
}
}
</style>

View file

@ -1,4 +1,15 @@
import DefaultTheme from 'vitepress/theme'
import { h } from 'vue'
import Typewriter from './components/Typewriter.vue'
import './style.css'
export default DefaultTheme;
export default {
extends: DefaultTheme,
Layout() {
return h(DefaultTheme.Layout, null, {
'home-hero-info': () => h(Typewriter, {
staticTitle: 'Warp'
})
})
}
}

View file

@ -24,12 +24,17 @@
--vp-c-danger-3: var(--vp-c-red-3);
--vp-c-danger-soft: var(--vp-c-red-soft);
--glass-nav-bg: rgba(255, 255, 255, 0.8);
--glass-sidebar-bg: rgba(255, 255, 255, 0.8);
--glass-border: rgba(0, 0, 0, 0.08);
--glass-shadow: 0 4px 20px rgba(0, 0, 0, 0.04);
--glass-blur: 0.4rem;
--glass-nav-bg: rgba(255, 255, 255, 0.7);
--glass-sidebar-bg: rgba(255, 255, 255, 0.7);
--glass-bg: rgba(255, 255, 255, 0.8);
--glass-border: rgba(0, 0, 0, 0.08);
--glass-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.08);
--glass-highlight: inset 0 1px 0 0 rgba(255, 255, 255, 0.6);
--glass-blur: 28px;
--glass-radius: 24px;
--glass-menu-radius: 12px;
--vp-c-bg: #ffffff;
--vp-c-bg-alt: #f8f9fa;
@ -55,10 +60,13 @@
}
.dark {
--glass-nav-bg: rgba(22, 22, 24, 0.7);
--glass-sidebar-bg: rgba(22, 22, 24, 0.7);
--glass-border: rgba(255, 255, 255, 0.12);
--glass-shadow: 0 4px 30px rgba(0, 0, 0, 0.5);
--glass-nav-bg: rgba(22, 22, 24, 0.6);
--glass-sidebar-bg: rgba(22, 22, 24, 0.6);
--glass-bg: rgba(30, 30, 35, 0.6);
--glass-border: rgba(255, 255, 255, 0.1);
--glass-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.5);
--glass-highlight: inset 0 1px 0 0 rgba(255, 255, 255, 0.1);
--vp-c-bg: #0f0f11;
--vp-c-bg-alt: #161618;
@ -73,73 +81,118 @@ body::before {
height: 100vh;
z-index: -1;
pointer-events: none;
background:
radial-gradient(circle at 100% 0%, rgba(254, 82, 52, 0.08), transparent 40%),
radial-gradient(circle at 0% 100%, rgba(79, 70, 229, 0.08), transparent 40%);
radial-gradient(circle at 100% 0%, rgba(254, 82, 52, 0.1), transparent 50%),
radial-gradient(circle at 0% 100%, rgba(79, 70, 229, 0.1), transparent 50%);
}
.dark body::before {
background:
radial-gradient(circle at 90% 10%, rgba(79, 70, 229, 0.15), transparent 50%),
radial-gradient(circle at 10% 90%, rgba(254, 82, 52, 0.08), transparent 40%);
radial-gradient(circle at 90% 10%, rgba(254, 82, 52, 0.15), transparent 60%),
radial-gradient(circle at 10% 90%, rgba(79, 70, 229, 0.12), transparent 50%);
}
.VPNav {
background-color: transparent !important;
}
.VPNav { background-color: transparent !important; }
.VPNavBar {
background-color: var(--glass-nav-bg) !important;
backdrop-filter: blur(var(--glass-blur));
-webkit-backdrop-filter: blur(var(--glass-blur));
border-bottom: 1px solid var(--glass-border);
backdrop-filter: saturate(180%) blur(var(--glass-blur)) !important;
-webkit-backdrop-filter: saturate(180%) blur(var(--glass-blur)) !important;
border-bottom: 1px solid var(--glass-border) !important;
box-shadow: var(--glass-shadow);
transition: background-color 0.3s ease, border-color 0.3s ease;
}
.VPNav .content-body {
background-color: transparent !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
border-bottom: none !important;
box-shadow: none !important;
}
.VPNav .content-body { background-color: transparent !important; backdrop-filter: none !important; }
.VPSidebar {
background-color: var(--glass-sidebar-bg) !important;
backdrop-filter: blur(var(--glass-blur));
-webkit-backdrop-filter: blur(var(--glass-blur));
border-right: 1px solid var(--glass-border);
}
.VPLocalNav {
background-color: var(--glass-nav-bg) !important;
backdrop-filter: blur(var(--glass-blur));
border-bottom: 1px solid var(--glass-border);
.VPNavBar .divider { display: none; }
.VPFlyout .menu {
background-color: var(--glass-bg) !important;
backdrop-filter: saturate(180%) blur(var(--glass-blur)) !important;
-webkit-backdrop-filter: saturate(180%) blur(var(--glass-blur)) !important;
border: 1px solid var(--glass-border) !important;
border-radius: var(--glass-menu-radius) !important;
box-shadow: var(--glass-shadow), var(--glass-highlight) !important;
padding: 6px !important;
overflow: hidden;
}
.VPNavScreen {
background-color: var(--vp-c-bg) !important;
.VPFlyout .VPMenu {
background: transparent !important;
border: none !important;
}
.VPMenu {
background-color: var(--glass-nav-bg) !important;
backdrop-filter: blur(var(--glass-blur));
-webkit-backdrop-filter: blur(var(--glass-blur));
border: 1px solid var(--glass-border);
box-shadow: var(--glass-shadow);
border-radius: 12px;
.VPFlyout .item.active .link,
.VPFlyout .item .link:hover {
background-color: rgba(255, 255, 255, 0.1) !important;
border-radius: 6px;
}
.VPNavBarTitle {
background-color: transparent !important;
.dark .VPFlyout .item.active .link,
.dark .VPFlyout .item .link:hover {
background-color: rgba(255, 255, 255, 0.05) !important;
}
.VPNavBar .divider {
opacity: 0.2;
.VPFeature {
background: var(--glass-bg) !important;
backdrop-filter: saturate(180%) blur(var(--glass-blur)) !important;
-webkit-backdrop-filter: saturate(180%) blur(var(--glass-blur)) !important;
border: 1px solid var(--glass-border) !important;
border-radius: var(--glass-radius) !important;
background-clip: padding-box !important;
box-shadow: var(--glass-shadow), var(--glass-highlight) !important;
transition: transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1),
border-color 0.3s ease,
box-shadow 0.3s ease !important;
}
.VPFeature:hover {
transform: translateY(-8px) scale(1.01);
border-color: rgba(255, 255, 255, 0.4) !important;
box-shadow: 0 24px 48px rgba(0, 0, 0, 0.25),
inset 0 1px 0 rgba(255, 255, 255, 0.2) !important;
}
.VPButton {
border-radius: 99px !important;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
font-weight: 600 !important;
transition: all 0.3s ease !important;
}
.VPButton.brand {
background: linear-gradient(135deg, var(--vp-c-brand-3), var(--vp-c-brand-1)) !important;
border: 1px solid rgba(255, 255, 255, 0.2) !important;
box-shadow: 0 4px 12px rgba(var(--vp-c-brand-rgb), 0.5), inset 0 1px 0 rgba(255,255,255,0.3) !important;
}
.VPButton.brand:hover {
transform: scale(1.05);
box-shadow: 0 8px 24px rgba(var(--vp-c-brand-rgb), 0.6);
}
.VPButton.alt {
background-color: rgba(255, 255, 255, 0.1) !important;
border: 1px solid var(--glass-border) !important;
color: var(--vp-c-text-1) !important;
}
.VPButton.alt:hover {
background-color: rgba(255, 255, 255, 0.15) !important;
transform: translateY(-2px);
}
@media (min-width: 640px) {
:root { --vp-home-hero-image-filter: blur(56px); }

View file

@ -4,8 +4,6 @@ layout: home
hero:
image:
src: "/warp.png"
name: "Warp"
text: "A very-fast & powerful networking library for Roblox."
actions:
- theme: brand
text: Get Started