chore : 베너변경
SpecialSource Frontend CD / deploy (push) Successful in 6s

This commit is contained in:
sungjin.choi
2026-05-28 17:19:30 +09:00
parent 97341aceb8
commit 1beac49b20
+26 -35
View File
@@ -170,12 +170,10 @@ const loginPw = ref('');
const activeMenu = ref('main'); const activeMenu = ref('main');
const authToken = ref(localStorage.getItem('token')); const authToken = ref(localStorage.getItem('token'));
// 글로벌 오버레이 레이어 상태 관리 변수
const isProcessing = ref(false); const isProcessing = ref(false);
const overlayProgress = ref(0); const overlayProgress = ref(0);
const overlayStatus = ref(''); const overlayStatus = ref('');
// 메뉴 아이템 배열
const menuItems = [ const menuItems = [
{ id: 'main', name: 'HOME' }, { id: 'main', name: 'HOME' },
{ id: 'youtube', name: 'YOUTUBE' }, { id: 'youtube', name: 'YOUTUBE' },
@@ -186,12 +184,9 @@ const menuItems = [
const isLoggedIn = computed(() => !!authToken.value); const isLoggedIn = computed(() => !!authToken.value);
// 🟢 [UPGRADE] 메뉴 이동 시 영화 같은 TUI 로딩바 시퀀스 구동
const changeMenu = (id) => { const changeMenu = (id) => {
// 이미 열려있는 메뉴를 다시 누르면 불필요한 시퀀스 방지 차단
if (activeMenu.value === id) return; if (activeMenu.value === id) return;
// 1) 즉시 화면 전체를 덮고 초기 세팅
isProcessing.value = true; isProcessing.value = true;
overlayProgress.value = 0; overlayProgress.value = 0;
overlayStatus.value = `INITIALIZING ROUTE ACCESS: /${id.toUpperCase()}...`; overlayStatus.value = `INITIALIZING ROUTE ACCESS: /${id.toUpperCase()}...`;
@@ -200,11 +195,9 @@ const changeMenu = (id) => {
termInstance.value.echo(`\n[[b;green;]>] NAVIGATING TO /${id.toUpperCase()}... INITIALIZING PIPELINE.`); termInstance.value.echo(`\n[[b;green;]>] NAVIGATING TO /${id.toUpperCase()}... INITIALIZING PIPELINE.`);
} }
// 2) 400ms 동안 빠르게 게이지를 채우는 인터벌 구동 (속도 체감 굿)
const interval = setInterval(() => { const interval = setInterval(() => {
overlayProgress.value += 5; overlayProgress.value += 5;
// 진행 수치별 리눅스 해커 감성 문구 전환
if (overlayProgress.value === 25) { if (overlayProgress.value === 25) {
overlayStatus.value = `ALLOCATING MEMORY BUFFER FOR VUE_COMPONENT...`; overlayStatus.value = `ALLOCATING MEMORY BUFFER FOR VUE_COMPONENT...`;
} }
@@ -212,12 +205,10 @@ const changeMenu = (id) => {
overlayStatus.value = `DECRYPTING INTERFACE LOGS & SECURE ASSETS...`; overlayStatus.value = `DECRYPTING INTERFACE LOGS & SECURE ASSETS...`;
} }
if (overlayProgress.value === 85) { if (overlayProgress.value === 85) {
// ★ 85% 지점 오버레이 베일 뒤에서 슥 메인 콘텐츠 메뉴를 스왑!
activeMenu.value = id; activeMenu.value = id;
overlayStatus.value = `MOUNTING VIRTUAL DOM TREE... SUCCESS.`; overlayStatus.value = `MOUNTING VIRTUAL DOM TREE... SUCCESS.`;
} }
// 100% 도달 완료 시 종료 세팅
if (overlayProgress.value >= 100) { if (overlayProgress.value >= 100) {
clearInterval(interval); clearInterval(interval);
@@ -225,15 +216,13 @@ const changeMenu = (id) => {
termInstance.value.echo(`[[b;green;][SUCCESS]] COMPONENT LOADED PERFECTLY.`); termInstance.value.echo(`[[b;green;][SUCCESS]] COMPONENT LOADED PERFECTLY.`);
} }
// 여운을 약간 준 뒤 부드럽게 창 닫기
setTimeout(() => { setTimeout(() => {
isProcessing.value = false; isProcessing.value = false;
}, 120); }, 120);
} }
}, 20); // 20ms * 20단계 = 총 400ms 로딩 스피드 보장 }, 20);
}; };
// 로그인 등 다른 비즈니스 로직에서 사용하는 동적 제어용 스크립트는 원본 유지
const triggerOverlayProcess = (durationMs, initialMsg) => { const triggerOverlayProcess = (durationMs, initialMsg) => {
isProcessing.value = true; isProcessing.value = true;
overlayProgress.value = 0; overlayProgress.value = 0;
@@ -361,17 +350,26 @@ onMounted(() => {
<style> <style>
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@500;700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@500;700&display=swap');
/* GNB, 버튼, 인풋, 아스키, 터미널까지 싹 다 개발자 폰트 대통합 */ /* GNB, 버튼, 인풋, 터미널 등 일반 텍스트 영역은 개발자 폰트 대통합 */
.homepage-wrapper, .homepage-wrapper,
.menu-btn, .menu-btn,
.nav-item, .nav-item,
.ascii-art,
.terminal-box, .terminal-box,
.tui-global-overlay, .tui-global-overlay,
.login-terminal-frame,
.project-item,
.about-text,
.contact-form,
:deep(.terminal), :deep(.terminal),
:deep(.terminal span) { :deep(.terminal span) {
font-family: 'JetBrains Mono', monospace !important; font-family: 'JetBrains Mono', monospace !important;
} }
/* 🌟 [핵심 수정] 웹 폰트(JetBrains) 서브셋에서 특수문자 선 기호(╔, ═, ╝)가 빠지는 버그 차단.
배너 영역만큼은 모바일 크롬 내장 순수 모노스페이스 스택으로 완전 분리하여 1:1 완벽 정렬 강제 유도 */
.ascii-art {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Courier New", monospace !important;
}
</style> </style>
<style scoped> <style scoped>
@@ -395,7 +393,7 @@ onMounted(() => {
.nav-menu { display: flex; gap: 20px; } .nav-menu { display: flex; gap: 20px; }
.menu-btn { .menu-btn {
background: none; border: none; color: #008800; background: none; border: none; color: #008800;
font-family: monospace; font-size: 16px; cursor: pointer; font-size: 16px; cursor: pointer;
transition: 0.3s; transition: 0.3s;
} }
.menu-btn:hover, .menu-btn.active { color: #00ff00; text-shadow: 0 0 10px #00ff00; } .menu-btn:hover, .menu-btn.active { color: #00ff00; text-shadow: 0 0 10px #00ff00; }
@@ -410,7 +408,6 @@ onMounted(() => {
padding: 6px 18px; padding: 6px 18px;
margin-left: 10px; margin-left: 10px;
cursor: pointer; cursor: pointer;
font-family: 'Courier New', Courier, monospace;
font-size: 13px; font-size: 13px;
box-shadow: 0 0 5px rgba(0, 255, 0, 0.3); box-shadow: 0 0 5px rgba(0, 255, 0, 0.3);
transition: 0.3s; transition: 0.3s;
@@ -420,7 +417,7 @@ onMounted(() => {
color: #00ff00 !important; color: #00ff00 !important;
box-shadow: 0 0 10px #00ff00; box-shadow: 0 0 10px #00ff00;
} }
.user-info { color: #008800 !important; font-size: 12px; margin-right: 15px; font-family: monospace; letter-spacing: 1px;} .user-info { color: #008800 !important; font-size: 12px; margin-right: 15px; letter-spacing: 1px;}
.status-dot { width: 8px; height: 8px; background: #ff3b3b; border-radius: 50%; box-shadow: 0 0 8px #ff3b3b; transition: 0.5s; } .status-dot { width: 8px; height: 8px; background: #ff3b3b; border-radius: 50%; box-shadow: 0 0 8px #ff3b3b; transition: 0.5s; }
.status-dot.secure-mode { background: #00ff00; box-shadow: 0 0 8px #00ff00; } .status-dot.secure-mode { background: #00ff00; box-shadow: 0 0 8px #00ff00; }
@@ -432,7 +429,7 @@ onMounted(() => {
flex-direction: column; flex-direction: column;
} }
.sub-page { max-width: 1000px; margin: 0 auto; padding-top: 15px; width: 100%; } .sub-page { max-width: 1000px; margin: 0 auto; padding-top: 15px; width: 100%; }
.page-title { font-family: monospace; border-bottom: 1px solid #113311; padding-bottom: 10px; margin-bottom: 20px; color: #00ff00;} .page-title { border-bottom: 1px solid #113311; padding-bottom: 10px; margin-bottom: 20px; color: #00ff00;}
/* 메인 홈 아스키 전광판 레이아웃 */ /* 메인 홈 아스키 전광판 레이아웃 */
.main-page { .main-page {
@@ -443,7 +440,6 @@ onMounted(() => {
position: relative; position: relative;
} }
/* 글로벌 오버레이 배경 암전 처리 레이어 CSS 스타일 */
.tui-global-overlay { .tui-global-overlay {
position: fixed; position: fixed;
top: 0; top: 0;
@@ -466,8 +462,6 @@ onMounted(() => {
position: relative; position: relative;
} }
.ascii-art { .ascii-art {
/* 🟢 [★변경] 시스템 폰트 대신, 다운로드한 정밀 고정폭 폰트를 최우선 적용 */
font-family: 'JetBrains Mono', monospace !important;
font-weight: bold; font-weight: bold;
white-space: pre; white-space: pre;
display: block; display: block;
@@ -514,7 +508,6 @@ iframe { width: 100%; height: 180px; border-radius: 4px; }
max-width: 550px; margin: 40px auto; max-width: 550px; margin: 40px auto;
border: 1px dashed #00ff00; padding: 35px; border: 1px dashed #00ff00; padding: 35px;
background: #020a02; box-shadow: 0 0 15px rgba(0, 255, 0, 0.1); background: #020a02; box-shadow: 0 0 15px rgba(0, 255, 0, 0.1);
font-family: 'Courier New', Courier, monospace;
} }
.login-gate-title { color: #00ff00; font-size: 20px; margin-bottom: 10px; font-weight: bold;} .login-gate-title { color: #00ff00; font-size: 20px; margin-bottom: 10px; font-weight: bold;}
.login-gate-desc { color: #008800; font-size: 12px; margin-bottom: 30px; line-height: 1.4; } .login-gate-desc { color: #008800; font-size: 12px; margin-bottom: 30px; line-height: 1.4; }
@@ -523,21 +516,21 @@ iframe { width: 100%; height: 180px; border-radius: 4px; }
.login-label { width: 120px; color: #00ff00; font-weight: bold; font-size: 14px; } .login-label { width: 120px; color: #00ff00; font-weight: bold; font-size: 14px; }
.login-input { .login-input {
flex: 1; background: none; border: none; color: #00ff00; flex: 1; background: none; border: none; color: #00ff00;
font-family: 'Courier New', Courier, monospace; font-size: 15px; outline: none; font-size: 15px; outline: none;
} }
.login-submit-btn { .login-submit-btn {
margin-top: 15px; background: none; border: 1px solid #00ff00; margin-top: 15px; background: none; border: 1px solid #00ff00;
color: #00ff00; padding: 12px; font-family: 'Courier New', Courier, monospace; color: #00ff00; padding: 12px;
font-size: 14px; font-weight: bold; cursor: pointer; transition: 0.3s; font-size: 14px; font-weight: bold; cursor: pointer; transition: 0.3s;
} }
.login-submit-btn:hover { background: #00ff00; color: #000; box-shadow: 0 0 15px #00ff00; } .login-submit-btn:hover { background: #00ff00; color: #000; box-shadow: 0 0 15px #00ff00; }
/* 프로젝트 리스트 */ /* 프로젝트 리스트 */
.project-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; } .project-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.project-item { border: 1px solid #113311; padding: 15px; background: #080808; font-family: monospace;} .project-item { border: 1px solid #113311; padding: 15px; background: #080808; }
.item-header { font-weight: bold; margin-bottom: 10px; color: #00ff00; } .item-header { font-weight: bold; margin-bottom: 10px; color: #00ff00; }
.about-text { font-family: monospace; line-height: 2; color: #00cc00;} .about-text { line-height: 2; color: #00cc00;}
.contact-form { font-family: monospace; line-height: 2; color: #00cc00;} .contact-form { line-height: 2; color: #00cc00;}
/* 애니메이션 트랜지션 */ /* 애니메이션 트랜지션 */
.fade-enter-active, .fade-leave-active { transition: opacity 0.25s ease; } .fade-enter-active, .fade-leave-active { transition: opacity 0.25s ease; }
@@ -548,7 +541,7 @@ iframe { width: 100%; height: 180px; border-radius: 4px; }
height: 300px; margin: 10px 40px 30px; height: 300px; margin: 10px 40px 30px;
border: 2px solid #1a1a1a; background: #0a0a0a; overflow: hidden; border: 2px solid #1a1a1a; background: #0a0a0a; overflow: hidden;
} }
.monitor-header { background: #151515; padding: 5px 15px; color: #555; display: flex; justify-content: space-between; font-family: monospace; font-size: 12px;} .monitor-header { background: #151515; padding: 5px 15px; color: #555; display: flex; justify-content: space-between; font-size: 12px;}
.monitor-status { color: #00aa00; animation: blink 2s infinite; } .monitor-status { color: #00aa00; animation: blink 2s infinite; }
.crt-screen-overlay { position: relative; height: calc(100% - 30px); background: #020802; } .crt-screen-overlay { position: relative; height: calc(100% - 30px); background: #020802; }
.crt-screen-overlay::before { .crt-screen-overlay::before {
@@ -559,11 +552,10 @@ iframe { width: 100%; height: 180px; border-radius: 4px; }
.terminal-box { width: 100%; height: 100%; padding: 10px; } .terminal-box { width: 100%; height: 100%; padding: 10px; }
:deep(.terminal), :deep(.terminal span) { :deep(.terminal), :deep(.terminal span) {
--color: #33ff33 !important; font-family: monospace !important; --color: #33ff33 !important;
text-shadow: 0 0 5px rgba(51, 255, 51, 0.6) !important; text-shadow: 0 0 5px rgba(51, 255, 51, 0.6) !important;
} }
/* 📱 반응형 분기점 */
/* 📱 반응형 분기점 */ /* 📱 반응형 분기점 */
@media screen and (max-width: 1100px) { @media screen and (max-width: 1100px) {
#videos-container { grid-template-columns: repeat(2, 1fr); } #videos-container { grid-template-columns: repeat(2, 1fr); }
@@ -574,7 +566,7 @@ iframe { width: 100%; height: 180px; border-radius: 4px; }
.project-grid { grid-template-columns: 1fr; } .project-grid { grid-template-columns: 1fr; }
.auth-nav { flex-direction: column; gap: 12px; padding: 15px 20px; } .auth-nav { flex-direction: column; gap: 12px; padding: 15px 20px; }
/* 유저님이 원하셨던 모바일 가로 스크롤 완벽 보장 설정 */ /* 🟢 [가로 스크롤 활성화] 원래 원하셨던 모바일 가로 스크롤 컨테이너 복구 */
.ascii-container { .ascii-container {
width: 100%; width: 100%;
overflow-x: auto !important; overflow-x: auto !important;
@@ -586,20 +578,19 @@ iframe { width: 100%; height: 180px; border-radius: 4px; }
} }
.ascii-art { .ascii-art {
font-size: 11px !important; /* 모바일 가로 스크롤 가독성 최적 크기 */ font-size: 10px !important; /* 가로 스크롤 시 한눈에 잡히는 모바일 최적 크기 */
line-height: 1.3 !important; line-height: 1.35 !important;
white-space: pre !important; white-space: pre !important;
word-break: keep-all !important; word-break: keep-all !important;
width: max-content !important; width: max-content !important;
margin: 0 !important; margin: 0 !important;
/* 갤럭시용 폰트 부스팅 버그 방어 */ /* 🟢 [치트키] 모바일 크롬이 글자 크기를 강제 보정해서 칼각을 찢어버리는 '폰트 부스팅' 버그 완벽 차단 */
-webkit-text-size-adjust: none !important; -webkit-text-size-adjust: none !important;
text-size-adjust: none !important; text-size-adjust: none !important;
max-height: 999999px !important; max-height: 999999px !important;
} }
} }
@keyframes blink { 0%, 100% { opacity: 0.4; } 50% { opacity: 1; } } @keyframes blink { 0%, 100% { opacity: 0.4; } 50% { opacity: 1; } }
/* 일회성 사이버 글리치 키프레임 */ /* 일회성 사이버 글리치 키프레임 */