feat: rotating headline with typing effect
- Add typing animation for hero headlines - Headlines: 거뜬합니다, 최적의 컨디션, 멈추지 않습니다, 아시아 전역 커버, AI가 합니다 - Remove progress dots for cleaner UI - Update regions: 도쿄 · 오사카 · 서울 · 싱가포르 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
119
index.html
119
index.html
@@ -3,11 +3,11 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
<title>Anvil Hosting - 개발자를 위한 컨테이너 클라우드</title>
|
<title>Anvil Hosting - 엔지니어가 관리하는 Linux 서버</title>
|
||||||
|
|
||||||
<!-- SEO Meta Tags -->
|
<!-- SEO Meta Tags -->
|
||||||
<meta name="description" content="Incus/LXD 기반 초경량 컨테이너 호스팅. VM 오버헤드 없이 네이티브 성능을 제공하며, n8n, Ansible 자동화 파이프라인과 즉시 연동됩니다.">
|
<meta name="description" content="엔지니어가 직접 튜닝한 Linux 서버. 웹, DB, API, 게임서버 뭐든 돌립니다. 고객의 문제가 해결될 때까지, 우리는 멈추지 않습니다.">
|
||||||
<meta name="keywords" content="컨테이너 호스팅, LXD, Incus, 클라우드 서버, VPS, 도쿄 서버, 서울 서버, 개발자 호스팅">
|
<meta name="keywords" content="Linux 서버, 클라우드 서버, VPS, 도쿄 서버, 서울 서버, 관리형 호스팅, 서버 호스팅">
|
||||||
<meta name="author" content="Anvil Hosting">
|
<meta name="author" content="Anvil Hosting">
|
||||||
<meta name="robots" content="index, follow">
|
<meta name="robots" content="index, follow">
|
||||||
<link rel="canonical" href="https://hosting.anvil.it.com">
|
<link rel="canonical" href="https://hosting.anvil.it.com">
|
||||||
@@ -15,8 +15,8 @@
|
|||||||
<!-- Open Graph -->
|
<!-- Open Graph -->
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:url" content="https://hosting.anvil.it.com">
|
<meta property="og:url" content="https://hosting.anvil.it.com">
|
||||||
<meta property="og:title" content="Anvil Hosting - 개발자를 위한 컨테이너 클라우드">
|
<meta property="og:title" content="Anvil Hosting - 엔지니어가 관리하는 Linux 서버">
|
||||||
<meta property="og:description" content="Incus/LXD 기반 초경량 컨테이너 호스팅. 네이티브 성능과 자동화 파이프라인을 경험하세요.">
|
<meta property="og:description" content="엔지니어가 직접 튜닝한 Linux 서버. 고객의 문제가 해결될 때까지, 우리는 멈추지 않습니다.">
|
||||||
<meta property="og:locale" content="ko_KR">
|
<meta property="og:locale" content="ko_KR">
|
||||||
|
|
||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
@@ -124,17 +124,14 @@
|
|||||||
/_/ \_\_| \_| \_/ |___|_____|
|
/_/ \_\_| \_| \_/ |___|_____|
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<!-- Main Headline -->
|
<!-- Main Headline with Rotation -->
|
||||||
<div class="space-y-4 max-w-4xl mt-4">
|
<div class="space-y-6 max-w-4xl mt-4" x-data="headlineRotator()">
|
||||||
<h1 class="text-2xl md:text-4xl lg:text-5xl font-display font-bold text-white tracking-tight leading-tight">
|
<div class="min-h-[120px] md:min-h-[160px] lg:min-h-[200px] flex flex-col justify-center">
|
||||||
<span class="text-terminal-muted mr-2">></span>Incus/LXD 기반<br/>
|
<h1 class="text-2xl md:text-4xl lg:text-5xl font-display font-bold text-white tracking-tight leading-tight">
|
||||||
<span class="text-terminal-muted mr-2">></span>초경량 컨테이너 호스팅<span class="text-primary cursor-blink text-3xl md:text-5xl align-middle ml-1">▋</span>
|
<span class="text-terminal-muted mr-2">></span><span x-text="displayedLine1"></span><span x-show="isTypingLine1" class="text-primary cursor-blink">_</span><br/>
|
||||||
</h1>
|
<span class="text-terminal-muted mr-2">></span><span class="text-primary" x-text="displayedLine2"></span><span x-show="isTypingLine2 || (!isTypingLine1 && !isTypingLine2)" class="text-primary cursor-blink">_</span>
|
||||||
<p class="text-terminal-muted text-base md:text-lg max-w-2xl border-l-2 border-terminal-border pl-4 mt-4">
|
</h1>
|
||||||
# VM 오버헤드 없이 네이티브 성능<br/>
|
</div>
|
||||||
# 하이퍼바이저 없는 순수 Linux 컨테이너<br/>
|
|
||||||
# 도쿄 · 서울 · 싱가포르 · 홍콩 리전
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Typing Carousel -->
|
<!-- Typing Carousel -->
|
||||||
@@ -375,6 +372,96 @@
|
|||||||
<!-- Alpine.js -->
|
<!-- Alpine.js -->
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.3/dist/cdn.min.js"></script>
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.3/dist/cdn.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
function headlineRotator() {
|
||||||
|
return {
|
||||||
|
headlines: [
|
||||||
|
{ line1: '웹, DB, API, 게임서버', line2: '거뜬합니다' },
|
||||||
|
{ line1: '엔지니어가 튜닝한', line2: '최적의 컨디션' },
|
||||||
|
{ line1: '고객의 문제가 해결될 때까지', line2: '우리는 멈추지 않습니다' },
|
||||||
|
{ line1: '도쿄 · 오사카 · 서울 · 싱가포르', line2: '아시아 전역 커버' },
|
||||||
|
{ line1: '복잡한 서버 관리는 이제 그만', line2: '지금부터 AI가 합니다' },
|
||||||
|
],
|
||||||
|
currentIndex: 0,
|
||||||
|
progress: 0,
|
||||||
|
displayedLine1: '',
|
||||||
|
displayedLine2: '',
|
||||||
|
isTypingLine1: true,
|
||||||
|
isTypingLine2: false,
|
||||||
|
typingId: null,
|
||||||
|
progressId: null,
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.startTyping();
|
||||||
|
},
|
||||||
|
|
||||||
|
startTyping() {
|
||||||
|
this.displayedLine1 = '';
|
||||||
|
this.displayedLine2 = '';
|
||||||
|
this.isTypingLine1 = true;
|
||||||
|
this.isTypingLine2 = false;
|
||||||
|
this.progress = 0;
|
||||||
|
|
||||||
|
if (this.typingId) clearInterval(this.typingId);
|
||||||
|
if (this.progressId) clearInterval(this.progressId);
|
||||||
|
|
||||||
|
const line1 = this.headlines[this.currentIndex].line1;
|
||||||
|
const line2 = this.headlines[this.currentIndex].line2;
|
||||||
|
let charIndex = 0;
|
||||||
|
|
||||||
|
// Type line 1
|
||||||
|
this.typingId = setInterval(() => {
|
||||||
|
if (charIndex < line1.length) {
|
||||||
|
this.displayedLine1 = line1.substring(0, charIndex + 1);
|
||||||
|
charIndex++;
|
||||||
|
} else {
|
||||||
|
clearInterval(this.typingId);
|
||||||
|
this.isTypingLine1 = false;
|
||||||
|
this.isTypingLine2 = true;
|
||||||
|
charIndex = 0;
|
||||||
|
|
||||||
|
// Type line 2
|
||||||
|
this.typingId = setInterval(() => {
|
||||||
|
if (charIndex < line2.length) {
|
||||||
|
this.displayedLine2 = line2.substring(0, charIndex + 1);
|
||||||
|
charIndex++;
|
||||||
|
} else {
|
||||||
|
clearInterval(this.typingId);
|
||||||
|
this.isTypingLine2 = false;
|
||||||
|
this.startProgress();
|
||||||
|
}
|
||||||
|
}, 60);
|
||||||
|
}
|
||||||
|
}, 60);
|
||||||
|
},
|
||||||
|
|
||||||
|
startProgress() {
|
||||||
|
this.progress = 0;
|
||||||
|
const duration = 3000;
|
||||||
|
const step = 100 / (duration / 50);
|
||||||
|
|
||||||
|
this.progressId = setInterval(() => {
|
||||||
|
this.progress += step;
|
||||||
|
if (this.progress >= 100) {
|
||||||
|
clearInterval(this.progressId);
|
||||||
|
this.next();
|
||||||
|
}
|
||||||
|
}, 50);
|
||||||
|
},
|
||||||
|
|
||||||
|
next() {
|
||||||
|
this.currentIndex = (this.currentIndex + 1) % this.headlines.length;
|
||||||
|
this.startTyping();
|
||||||
|
},
|
||||||
|
|
||||||
|
goTo(index) {
|
||||||
|
if (this.typingId) clearInterval(this.typingId);
|
||||||
|
if (this.progressId) clearInterval(this.progressId);
|
||||||
|
this.currentIndex = index;
|
||||||
|
this.startTyping();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function typingCarousel() {
|
function typingCarousel() {
|
||||||
return {
|
return {
|
||||||
commands: [
|
commands: [
|
||||||
|
|||||||
Reference in New Issue
Block a user