release
This commit is contained in:
+89
-12
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user