This commit is contained in:
SeoJHeasdw
2025-06-11 17:37:52 +09:00
parent df016023be
commit a9005e6dc4
7 changed files with 512 additions and 505 deletions
+89 -12
View File
@@ -16,6 +16,9 @@ import * as directives from 'vuetify/directives'
import { mdi } from 'vuetify/iconsets/mdi'
import '@mdi/font/css/materialdesignicons.css'
// 전역 스타일
import './styles/main.scss'
// Vuetify 테마 설정
const vuetify = createVuetify({
components,
@@ -32,17 +35,32 @@ const vuetify = createVuetify({
info: '#2196F3',
success: '#4CAF50',
warning: '#FFC107',
background: '#F5F5F5',
surface: '#FFFFFF'
}
}
}
background: '#FFFFFF',
surface: '#FFFFFF',
'surface-variant': '#F5F5F5',
},
},
dark: {
colors: {
primary: '#2196F3',
secondary: '#616161',
accent: '#82B1FF',
error: '#FF5252',
info: '#2196F3',
success: '#4CAF50',
warning: '#FFC107',
background: '#121212',
surface: '#1E1E1E',
'surface-variant': '#424242',
},
},
},
},
icons: {
defaultSet: 'mdi',
sets: {
mdi
}
mdi,
},
},
display: {
mobileBreakpoint: 'sm',
@@ -51,15 +69,74 @@ const vuetify = createVuetify({
sm: 600,
md: 960,
lg: 1280,
xl: 1920
}
}
xl: 1920,
},
},
defaults: {
VCard: {
elevation: 2,
rounded: 'lg',
},
VBtn: {
rounded: 'lg',
},
VTextField: {
variant: 'outlined',
density: 'comfortable',
},
VSelect: {
variant: 'outlined',
density: 'comfortable',
},
VTextarea: {
variant: 'outlined',
density: 'comfortable',
},
},
})
// Pinia 스토어 생성
const pinia = createPinia()
// Vue 앱 생성
const app = createApp(App)
app.use(createPinia())
// 전역 속성 설정
app.config.globalProperties.$config = window.__runtime_config__ || {}
// 에러 핸들링
app.config.errorHandler = (err, instance, info) => {
console.error('Vue 앱 에러:', err, info)
// 프로덕션 환경에서 에러 리포팅
if (import.meta.env.PROD) {
// 에러 리포팅 서비스에 전송
// reportError(err, instance, info)
}
}
// 플러그인 등록
app.use(pinia)
app.use(router)
app.use(vuetify)
app.mount('#app')
// 개발 모드 설정
if (import.meta.env.DEV) {
app.config.performance = true
window.__VUE_DEVTOOLS_GLOBAL_HOOK__ = window.__VUE_DEVTOOLS_GLOBAL_HOOK__ || {}
}
// 앱 마운트
app.mount('#app')
// 서비스 워커 등록 (프로덕션에서만)
if (import.meta.env.PROD && 'serviceWorker' in navigator) {
window.addEventListener('load', async () => {
try {
const registration = await navigator.serviceWorker.register('/sw.js')
console.log('서비스 워커 등록 성공:', registration)
} catch (error) {
console.log('서비스 워커 등록 실패:', error)
}
})
}
+256
View File
@@ -0,0 +1,256 @@
//* src/styles/main.scss
/**
* 메인 스타일시트
* 전역 스타일 및 커스텀 스타일 정의
*/
// 변수 정의
:root {
--primary-color: #1976d2;
--secondary-color: #424242;
--success-color: #4caf50;
--warning-color: #ffc107;
--error-color: #ff5252;
--info-color: #2196f3;
--background-color: #ffffff;
--surface-color: #ffffff;
--surface-variant-color: #f5f5f5;
--text-primary: #212121;
--text-secondary: #757575;
--text-disabled: #bdbdbd;
--border-color: #e0e0e0;
--divider-color: #f5f5f5;
--shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.1);
--shadow-md: 0 4px 8px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 8px 16px rgba(0, 0, 0, 0.1);
--border-radius-sm: 4px;
--border-radius-md: 8px;
--border-radius-lg: 12px;
--border-radius-xl: 16px;
--transition-fast: 0.15s ease;
--transition-normal: 0.3s ease;
--transition-slow: 0.5s ease;
}
// 다크 테마 변수
[data-theme='dark'] {
--background-color: #121212;
--surface-color: #1e1e1e;
--surface-variant-color: #424242;
--text-primary: #ffffff;
--text-secondary: #aaaaaa;
--text-disabled: #666666;
--border-color: #333333;
--divider-color: #2a2a2a;
}
// 기본 스타일 리셋
* {
box-sizing: border-box;
}
html {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
scroll-behavior: smooth;
}
body {
margin: 0;
padding: 0;
font-family: 'Roboto', 'Noto Sans KR', sans-serif;
background-color: var(--background-color);
color: var(--text-primary);
line-height: 1.6;
}
// 링크 스타일
a {
color: var(--primary-color);
text-decoration: none;
transition: var(--transition-fast);
&:hover {
opacity: 0.8;
}
}
// 버튼 공통 스타일
.btn-gradient {
background: linear-gradient(135deg, var(--primary-color), #1565c0);
color: white;
border: none;
transition: var(--transition-normal);
&:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
}
}
// 카드 스타일
.card-hover {
transition: var(--transition-normal);
&:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-lg);
}
}
// 유틸리티 클래스
.text-truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.text-truncate-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.text-truncate-3 {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
// 스크롤바 스타일
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: var(--surface-variant-color);
border-radius: var(--border-radius-md);
}
::-webkit-scrollbar-thumb {
background: var(--border-color);
border-radius: var(--border-radius-md);
&:hover {
background: var(--text-secondary);
}
}
// 로딩 애니메이션
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
.loading-pulse {
animation: pulse 2s infinite;
}
// 페이드 인 애니메이션
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.fade-in {
animation: fadeIn var(--transition-normal);
}
// 반응형 유틸리티
@media (max-width: 600px) {
.mobile-hide {
display: none !important;
}
.mobile-full-width {
width: 100% !important;
}
}
@media (min-width: 601px) {
.desktop-hide {
display: none !important;
}
}
// 접근성 개선
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
// 포커스 스타일 개선
.focus-outline {
&:focus {
outline: 2px solid var(--primary-color);
outline-offset: 2px;
}
}
// 인쇄 스타일
@media print {
.no-print {
display: none !important;
}
.v-navigation-drawer,
.v-app-bar,
.v-bottom-navigation {
display: none !important;
}
.v-main {
padding: 0 !important;
}
}
// 고대비 모드 지원
@media (prefers-contrast: high) {
:root {
--border-color: #000000;
--text-secondary: #000000;
}
[data-theme='dark'] {
--border-color: #ffffff;
--text-secondary: #ffffff;
}
}
// 움직임 줄이기 설정 존중
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}