- Add scene_onboarding.html, scene_dashboard.html, scene_settings.html - Add onboarding.js, dashboard.js, settings.js scripts - Update vite.config.js for multi-page build - Navigation via window.location.href between pages - Bottom nav bar on dashboard only
933 lines
55 KiB
HTML
933 lines
55 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Chakmate - 지능형 디지털 자산 관리</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&family=Outfit:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<svg xmlns="http://www.w3.org/2000/svg" style="display: none">
|
|
<symbol id="icon-layers" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
|
|
<path d="M2 17l10 5 10-5"/>
|
|
<path d="M2 12l10 5 10-5"/>
|
|
</symbol>
|
|
<symbol id="icon-shield-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
|
|
<path d="M9 12l2 2 4-4"/>
|
|
</symbol>
|
|
<symbol id="icon-arrow-right" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M5 12h14"/>
|
|
<path d="M12 5l7 7-7 7"/>
|
|
</symbol>
|
|
<symbol id="icon-star" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
|
|
</symbol>
|
|
<symbol id="icon-fire" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z"/>
|
|
<path d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z"/>
|
|
</symbol>
|
|
<symbol id="icon-cog" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M12 15a3 3 0 100-6 3 3 0 000 6z"/>
|
|
<path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z"/>
|
|
</symbol>
|
|
<symbol id="icon-document" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/>
|
|
<path d="M14 2v6h6"/>
|
|
<path d="M16 13H8"/>
|
|
<path d="M16 17H8"/>
|
|
<path d="M10 9H8"/>
|
|
</symbol>
|
|
<symbol id="icon-folder" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z"/>
|
|
</symbol>
|
|
<symbol id="icon-bolt" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/>
|
|
</symbol>
|
|
<symbol id="icon-light-bulb" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/>
|
|
</symbol>
|
|
<symbol id="icon-trash" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M3 6h18"/>
|
|
<path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/>
|
|
</symbol>
|
|
<symbol id="icon-arrow-left" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M19 12H5"/>
|
|
<path d="M12 19l-7-7 7-7"/>
|
|
</symbol>
|
|
<symbol id="icon-chevron-right" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M9 18l6-6-6-6"/>
|
|
</symbol>
|
|
<symbol id="icon-x-mark" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M18 6L6 18"/>
|
|
<path d="M6 6l12 12"/>
|
|
</symbol>
|
|
<symbol id="icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M20 6L9 17l-5-5"/>
|
|
</symbol>
|
|
<symbol id="icon-photo" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
|
|
<circle cx="8.5" cy="8.5" r="1.5"/>
|
|
<polyline points="21 15 16 10 5 21"/>
|
|
</symbol>
|
|
<symbol id="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<circle cx="12" cy="12" r="5"/>
|
|
<line x1="12" y1="1" x2="12" y2="3"/>
|
|
<line x1="12" y1="21" x2="12" y2="23"/>
|
|
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
|
|
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
|
|
<line x1="1" y1="12" x2="3" y2="12"/>
|
|
<line x1="21" y1="12" x2="23" y2="12"/>
|
|
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
|
|
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
|
|
</symbol>
|
|
<symbol id="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/>
|
|
</symbol>
|
|
<symbol id="icon-download" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/>
|
|
<path d="M7 10l5 5 5-5"/>
|
|
<path d="M12 15V3"/>
|
|
</symbol>
|
|
<symbol id="icon-undo" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M3 10h10a5 5 0 015 5v0a5 5 0 01-5 5H3"/>
|
|
<path d="M3 10l4-4"/>
|
|
<path d="M3 10l4 4"/>
|
|
</symbol>
|
|
</svg>
|
|
<script>
|
|
tailwind.config = {
|
|
theme: {
|
|
extend: {
|
|
colors: {
|
|
primary: { DEFAULT: '#3b82f6', light: '#60a5fa', dark: '#1d4ed8' },
|
|
secondary: { DEFAULT: '#06b6d4', light: '#22d3ee' },
|
|
accent: { DEFAULT: '#0ea5e9', warn: '#38bdf8', danger: '#f472b6' },
|
|
surface: { primary: '#f8fafc', secondary: '#e2e8f0', card: '#ffffff' },
|
|
text: { primary: '#0f172a', secondary: '#475569', muted: '#94a3b8' },
|
|
},
|
|
fontFamily: {
|
|
sans: ['Noto Sans KR', '-apple-system', 'BlinkMacSystemFont', 'sans-serif'],
|
|
display: ['Outfit', 'sans-serif'],
|
|
},
|
|
boxShadow: {
|
|
'sm': '0 2px 8px rgba(14, 165, 233, 0.06)',
|
|
'md': '0 4px 20px rgba(14, 165, 233, 0.08)',
|
|
'lg': '0 8px 40px rgba(14, 165, 233, 0.12)',
|
|
'glow': '0 0 30px rgba(14, 165, 233, 0.25)',
|
|
'blue': '0 4px 20px rgba(59, 130, 246, 0.3)',
|
|
},
|
|
animation: {
|
|
'float': 'float 3s ease-in-out infinite',
|
|
'fade-slide-up': 'fadeSlideUp 0.5s ease forwards',
|
|
'slide-in': 'slideIn 0.5s ease forwards',
|
|
'bounce-in': 'bounceIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) forwards',
|
|
'pulse-slow': 'pulse 2s ease-in-out infinite',
|
|
},
|
|
keyframes: {
|
|
float: {
|
|
'0%, 100%': { transform: 'translateY(0)' },
|
|
'50%': { transform: 'translateY(-10px)' },
|
|
},
|
|
fadeSlideUp: {
|
|
from: { opacity: '0', transform: 'translateY(20px)' },
|
|
to: { opacity: '1', transform: 'translateY(0)' },
|
|
},
|
|
slideIn: {
|
|
from: { opacity: '0', transform: 'translateY(30px)' },
|
|
to: { opacity: '1', transform: 'translateY(0)' },
|
|
},
|
|
bounceIn: {
|
|
'0%': { transform: 'scale(0)' },
|
|
'50%': { transform: 'scale(1.1)' },
|
|
'100%': { transform: 'scale(1)' },
|
|
},
|
|
pulse: {
|
|
'0%, 100%': { opacity: '0.5', transform: 'scale(1)' },
|
|
'50%': { opacity: '1', transform: 'scale(1.1)' },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
<style>
|
|
[data-theme="dark"] {
|
|
--bg-primary: #0a0e1a;
|
|
--bg-secondary: #111827;
|
|
--bg-card: #1e293b;
|
|
--bg-overlay: rgba(14, 165, 233, 0.12);
|
|
--text-primary: #f1f5f9;
|
|
--text-secondary: #94a3b8;
|
|
--text-muted: #64748b;
|
|
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.4);
|
|
--shadow-md: 0 4px 20px rgba(0, 0, 0, 0.5);
|
|
--shadow-lg: 0 8px 40px rgba(0, 0, 0, 0.6);
|
|
--shadow-glow: 0 0 30px rgba(14, 165, 233, 0.3);
|
|
}
|
|
[data-theme="dark"] body { background: var(--bg-primary); color: var(--text-primary); }
|
|
[data-theme="dark"] .bg-primary { background: var(--bg-primary); }
|
|
[data-theme="dark"] .bg-secondary { background: var(--bg-secondary); }
|
|
[data-theme="dark"] .bg-card { background: var(--bg-card); }
|
|
[data-theme="dark"] .bg-overlay { background: var(--bg-overlay); }
|
|
[data-theme="dark"] .text-primary { color: var(--text-primary); }
|
|
[data-theme="dark"] .text-secondary { color: var(--text-secondary); }
|
|
[data-theme="dark"] .text-muted { color: var(--text-muted); }
|
|
[data-theme="dark"] .shadow-sm { box-shadow: var(--shadow-sm); }
|
|
[data-theme="dark"] .shadow-md { box-shadow: var(--shadow-md); }
|
|
[data-theme="dark"] .shadow-lg { box-shadow: var(--shadow-lg); }
|
|
[data-theme="dark"] .shadow-glow { box-shadow: var(--shadow-glow); }
|
|
[data-theme="dark"] .border-secondary { border-color: var(--bg-secondary); }
|
|
[data-theme="dark"] .bg-primary { background-color: var(--primary); }
|
|
|
|
/* Onboarding step-dot active state */
|
|
.step-dot.active {
|
|
width: 32px;
|
|
background-color: #3b82f6;
|
|
}
|
|
|
|
/* Onboarding step content visibility */
|
|
.onboarding-step {
|
|
display: none;
|
|
}
|
|
.onboarding-step.active {
|
|
display: block;
|
|
}
|
|
|
|
/* Screen visibility */
|
|
.screen {
|
|
display: none;
|
|
}
|
|
.screen.active {
|
|
display: block;
|
|
}
|
|
|
|
/* Button styles */
|
|
.btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 0.5rem;
|
|
padding: 1rem 2rem;
|
|
border-radius: 9999px;
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
border: none;
|
|
transition: all 0.25s ease;
|
|
}
|
|
.btn-primary {
|
|
background: linear-gradient(135deg, #3b82f6 0%, #06b6d4 100%);
|
|
color: white;
|
|
box-shadow: 0 4px 20px rgba(59, 130, 246, 0.3);
|
|
}
|
|
.btn-primary:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 6px 25px rgba(59, 130, 246, 0.4);
|
|
}
|
|
.btn-secondary {
|
|
background: #e2e8f0;
|
|
color: #0f172a;
|
|
}
|
|
.btn-icon {
|
|
width: 44px;
|
|
height: 44px;
|
|
padding: 0;
|
|
border-radius: 12px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="font-sans bg-surface-primary text-text-primary min-h-screen antialiased overflow-x-hidden">
|
|
<!-- Onboarding Screen -->
|
|
<div id="onboarding" class="screen active">
|
|
<div class="max-w-[420px] w-full text-center flex flex-col items-center justify-center min-h-screen p-4 gap-4 lg:flex-row lg:max-w-full lg:justify-center lg:gap-8">
|
|
<div class="flex flex-col items-center justify-center lg:flex-shrink-0">
|
|
<div class="logo w-64 h-64 mx-auto mb-6 flex items-center justify-center animate-float lg:w-48 lg:h-48">
|
|
<img src="assets/logo.svg" alt="Chakmate Logo" class="w-full h-full object-contain">
|
|
</div>
|
|
<h1 class="brand-name font-display text-4xl font-bold bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent mb-2 lg:text-3xl">Chakmate</h1>
|
|
<p class="tagline text-text-secondary text-base mb-10 lg:mb-0">지능형 디지털 자산 관리 솔루션</p>
|
|
</div>
|
|
|
|
<div class="flex flex-col items-center gap-4 lg:flex-col">
|
|
<div class="steps-indicator flex gap-2 justify-center mb-8 lg:mb-0">
|
|
<div class="step-dot active w-2 h-2 rounded-full bg-text-muted transition-all duration-250" data-step="1"></div>
|
|
<div class="step-dot w-2 h-2 rounded-full bg-text-muted transition-all duration-250" data-step="2"></div>
|
|
<div class="step-dot w-2 h-2 rounded-full bg-text-muted transition-all duration-250" data-step="3"></div>
|
|
</div>
|
|
|
|
<!-- Step 1: Welcome -->
|
|
<div class="onboarding-step active" data-step="1">
|
|
<div class="step-illustration w-[200px] h-[200px] mx-auto mb-8 bg-surface-card rounded-[28px] flex items-center justify-center shadow-lg relative overflow-hidden">
|
|
<div class="absolute inset-0 bg-gradient-to-br from-accent/10 to-transparent"></div>
|
|
<svg class="w-[100px] h-[100px] stroke-primary fill-none stroke-[1.5] relative z-10"><use href="#icon-layers"></use></svg>
|
|
</div>
|
|
<h2 class="step-title text-xl mb-3 text-text-primary font-display">파일 정리, 지능적으로</h2>
|
|
<p class="step-desc text-text-secondary leading-relaxed mb-8">AI가 파일 사용 패턴을 분석하여 당신만의 최적화된 폴더 구조를 제안합니다. 더 이상 수동 정리는 필요 없습니다.</p>
|
|
<div class="privacy-badge inline-flex items-center gap-2 bg-accent text-white px-4 py-2 rounded-full text-sm font-medium mb-6">
|
|
<svg class="w-4 h-4 stroke-white fill-none"><use href="#icon-shield-check"></use></svg>
|
|
<span>기기 내 단독 처리 • 완벽한 개인정보 보호</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 2: Swipe -->
|
|
<div class="onboarding-step hidden" data-step="2">
|
|
<div class="step-illustration w-[200px] h-[200px] mx-auto mb-8 bg-surface-card rounded-[28px] flex items-center justify-center shadow-lg relative overflow-hidden">
|
|
<div class="absolute inset-0 bg-gradient-to-br from-accent/10 to-transparent"></div>
|
|
<svg class="w-[100px] h-[100px] stroke-primary fill-none stroke-[1.5] relative z-10"><use href="#icon-arrow-right"></use></svg>
|
|
</div>
|
|
<h2 class="step-title text-xl mb-3 text-text-primary font-display">스와이프로 직관적으로</h2>
|
|
<p class="step-desc text-text-secondary leading-relaxed mb-8">오른쪽 스와이프로 보관, 왼쪽 스와이프로 삭제. 카드形式的 인터페이스로 누구나 쉽게 파일을 정리할 수 있습니다.</p>
|
|
</div>
|
|
|
|
<!-- Step 3: Gamification -->
|
|
<div class="onboarding-step hidden" data-step="3">
|
|
<div class="step-illustration w-[200px] h-[200px] mx-auto mb-8 bg-surface-card rounded-[28px] flex items-center justify-center shadow-lg relative overflow-hidden">
|
|
<div class="absolute inset-0 bg-gradient-to-br from-accent/10 to-transparent"></div>
|
|
<svg class="w-[100px] h-[100px] stroke-primary fill-none stroke-[1.5] relative z-10"><use href="#icon-star"></use></svg>
|
|
</div>
|
|
<h2 class="step-title text-xl mb-3 text-text-primary font-display">습관 형성의 재미</h2>
|
|
<p class="step-desc text-text-secondary leading-relaxed mb-8">매일 정리하고 스트릭을 쌓아보세요. 업적 배지를 수집하고 디지털 공간을 항상 청결하게 유지하세요.</p>
|
|
</div>
|
|
|
|
<div class="nav-buttons flex gap-4 justify-center mt-8">
|
|
<button class="btn btn-primary" id="onboarding-next">
|
|
<span>계속</span>
|
|
<svg class="w-5 h-5 stroke-current fill-none"><use href="#icon-arrow-right"></use></svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Dashboard Screen -->
|
|
<div id="dashboard" class="screen">
|
|
<div class="dashboard-container w-full min-h-screen flex flex-col">
|
|
<header class="header flex items-center justify-between p-4 lg:p-6 bg-surface-card shadow-sm sticky top-0 z-50">
|
|
<div class="header-left flex items-center gap-3">
|
|
<div class="header-logo w-20 h-20 flex items-center justify-center">
|
|
<img src="assets/logo.svg" alt="Chakmate Logo" class="w-full h-full object-contain">
|
|
</div>
|
|
<h1 class="header-title font-display text-xl font-semibold">Chakmate</h1>
|
|
</div>
|
|
<div class="header-right flex items-center gap-3">
|
|
<div class="streak-badge flex items-center gap-2 bg-gradient-to-r from-accent-warn to-amber-500 text-white px-4 py-2 rounded-full font-semibold text-sm" id="streak-display">
|
|
<svg class="w-[18px] h-[18px] stroke-current fill-none"><use href="#icon-fire"></use></svg>
|
|
<span id="streak-count">7</span>
|
|
</div>
|
|
<button class="btn btn-icon btn-secondary" id="settings-btn">
|
|
<svg class="w-5 h-5 stroke-current fill-none"><use href="#icon-cog"></use></svg>
|
|
</button>
|
|
</div>
|
|
</header>
|
|
|
|
<main class="main-content flex-1 p-6 grid grid-cols-1 lg:grid-cols-[1fr_380px] gap-6 max-w-[1400px] mx-auto w-full">
|
|
<div class="left-panel">
|
|
<div class="stats-grid grid grid-cols-1 sm:grid-cols-3 gap-4 mb-6">
|
|
<div class="stat-card bg-surface-card rounded-[20px] p-5 shadow-sm hover:-translate-y-1 hover:shadow-md transition-all duration-250 animate-slide-in">
|
|
<div class="stat-icon w-12 h-12 rounded-[12px] flex items-center justify-center mb-3 bg-primary/10">
|
|
<svg class="w-6 h-6 stroke-primary fill-none"><use href="#icon-document"></use></svg>
|
|
</div>
|
|
<div class="stat-value font-display text-3xl font-bold text-text-primary mb-1" id="files-organized">248</div>
|
|
<div class="stat-label text-text-secondary text-sm">정리된 파일</div>
|
|
</div>
|
|
<div class="stat-card bg-surface-card rounded-[20px] p-5 shadow-sm hover:-translate-y-1 hover:shadow-md transition-all duration-250 animate-slide-in" style="animation-delay: 0.1s">
|
|
<div class="stat-icon w-12 h-12 rounded-[12px] flex items-center justify-center mb-3 bg-pink-500/10">
|
|
<svg class="w-6 h-6 stroke-secondary fill-none"><use href="#icon-folder"></use></svg>
|
|
</div>
|
|
<div class="stat-value font-display text-3xl font-bold text-text-primary mb-1" id="folders-managed">12</div>
|
|
<div class="stat-label text-text-secondary text-sm">관리 중인 폴더</div>
|
|
</div>
|
|
<div class="stat-card bg-surface-card rounded-[20px] p-5 shadow-sm hover:-translate-y-1 hover:shadow-md transition-all duration-250 animate-slide-in" style="animation-delay: 0.2s">
|
|
<div class="stat-icon w-12 h-12 rounded-[12px] flex items-center justify-center mb-3 bg-emerald-500/10">
|
|
<svg class="w-6 h-6 stroke-accent-warn fill-none stroke-2"><use href="#icon-arrow-right"></use></svg>
|
|
</div>
|
|
<div class="stat-value font-display text-3xl font-bold text-text-primary mb-1" id="current-streak">7일</div>
|
|
<div class="stat-label text-text-secondary text-sm">현재 스트릭</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="file-view bg-surface-card rounded-[28px] shadow-md p-6 min-h-[400px]">
|
|
<div class="file-view-header flex items-center justify-between mb-5">
|
|
<h2 class="file-view-title text-xl flex items-center gap-2 font-display">
|
|
<svg class="w-6 h-6 stroke-primary fill-none"><use href="#icon-folder"></use></svg>
|
|
파일 구조
|
|
</h2>
|
|
<button class="btn btn-ghost" id="view-all-btn">전체 보기</button>
|
|
</div>
|
|
<div class="tree-view flex flex-col gap-2" id="file-tree"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="suggestions-panel flex flex-col gap-5">
|
|
<div class="panel-card bg-surface-card rounded-[28px] shadow-md p-6">
|
|
<div class="panel-header flex items-center gap-3 mb-5">
|
|
<div class="panel-icon w-11 h-11 rounded-[12px] flex items-center justify-center bg-gradient-to-br from-primary to-primary-light">
|
|
<svg class="w-[22px] h-[22px] stroke-white fill-none"><use href="#icon-light-bulb"></use></svg>
|
|
</div>
|
|
<div>
|
|
<h3 class="panel-title text-lg font-display">AI 구조 제안</h3>
|
|
<p class="panel-subtitle text-sm text-text-secondary">파일 패턴 분석 결과</p>
|
|
</div>
|
|
</div>
|
|
<div class="suggestion-list flex flex-col gap-3" id="suggestion-list"></div>
|
|
<button class="btn btn-primary apply-btn w-full mt-4" id="apply-suggestions">
|
|
<svg class="w-5 h-5 stroke-current fill-none"><use href="#icon-arrow-right"></use></svg>
|
|
<span>적용하기</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="panel-card bg-surface-card rounded-[28px] shadow-md p-6">
|
|
<div class="panel-header flex items-center gap-3 mb-5">
|
|
<div class="panel-icon w-11 h-11 rounded-[12px] flex items-center justify-center bg-gradient-to-br from-secondary to-secondary-light">
|
|
<svg class="w-[22px] h-[22px] stroke-white fill-none"><use href="#icon-bolt"></use></svg>
|
|
</div>
|
|
<div>
|
|
<h3 class="panel-title text-lg font-display">빠른 실행</h3>
|
|
<p class="panel-subtitle text-sm text-text-secondary">개별 Scene 실행</p>
|
|
</div>
|
|
</div>
|
|
<div class="quick-actions flex flex-col gap-3">
|
|
<a href="scene_swipe.html" class="quick-action-btn flex items-center gap-4 p-3 bg-surface-secondary rounded-[12px] text-text-primary hover:bg-overlay hover:translate-x-1 transition-all duration-150 no-underline">
|
|
<div class="quick-action-icon w-11 h-11 rounded-[12px] flex items-center justify-center flex-shrink-0 bg-gradient-to-br from-primary to-primary-dark">
|
|
<svg class="w-[22px] h-[22px] stroke-white fill-none"><use href="#icon-arrow-right"></use></svg>
|
|
</div>
|
|
<div class="quick-action-info flex-1 flex flex-col gap-0.5">
|
|
<span class="quick-action-title font-semibold text-sm">스와이프 모드</span>
|
|
<span class="quick-action-desc text-xs text-text-secondary">스와이프로 파일 정리</span>
|
|
</div>
|
|
<svg class="quick-action-arrow w-5 h-5 stroke-text-muted fill-none"><use href="#icon-chevron-right"></use></svg>
|
|
</a>
|
|
<a href="scene_ai_classification.html" class="quick-action-btn flex items-center gap-4 p-3 bg-surface-secondary rounded-[12px] text-text-primary hover:bg-overlay hover:translate-x-1 transition-all duration-150 no-underline">
|
|
<div class="quick-action-icon w-11 h-11 rounded-[12px] flex items-center justify-center flex-shrink-0 bg-gradient-to-br from-secondary to-secondary-light">
|
|
<svg class="w-[22px] h-[22px] stroke-white fill-none"><use href="#icon-light-bulb"></use></svg>
|
|
</div>
|
|
<div class="quick-action-info flex-1 flex flex-col gap-0.5">
|
|
<span class="quick-action-title font-semibold text-sm">AI 분류</span>
|
|
<span class="quick-action-desc text-xs text-text-secondary">AI 분석 및 패턴 인식</span>
|
|
</div>
|
|
<svg class="quick-action-arrow w-5 h-5 stroke-text-muted fill-none"><use href="#icon-chevron-right"></use></svg>
|
|
</a>
|
|
<a href="scene_visualization.html" class="quick-action-btn flex items-center gap-4 p-3 bg-surface-secondary rounded-[12px] text-text-primary hover:bg-overlay hover:translate-x-1 transition-all duration-150 no-underline">
|
|
<div class="quick-action-icon w-11 h-11 rounded-[12px] flex items-center justify-center flex-shrink-0 bg-gradient-to-br from-accent to-emerald-500">
|
|
<svg class="w-[22px] h-[22px] stroke-white fill-none"><use href="#icon-folder"></use></svg>
|
|
</div>
|
|
<div class="quick-action-info flex-1 flex flex-col gap-0.5">
|
|
<span class="quick-action-title font-semibold text-sm">구조 제안</span>
|
|
<span class="quick-action-desc text-xs text-text-secondary">폴더 구조 시각화</span>
|
|
</div>
|
|
<svg class="quick-action-arrow w-5 h-5 stroke-text-muted fill-none"><use href="#icon-chevron-right"></use></svg>
|
|
</a>
|
|
<a href="scene_gamification.html" class="quick-action-btn flex items-center gap-4 p-3 bg-surface-secondary rounded-[12px] text-text-primary hover:bg-overlay hover:translate-x-1 transition-all duration-150 no-underline">
|
|
<div class="quick-action-icon w-11 h-11 rounded-[12px] flex items-center justify-center flex-shrink-0 bg-gradient-to-br from-accent-warn to-amber-500">
|
|
<svg class="w-[22px] h-[22px] stroke-white fill-none"><use href="#icon-fire"></use></svg>
|
|
</div>
|
|
<div class="quick-action-info flex-1 flex flex-col gap-0.5">
|
|
<span class="quick-action-title font-semibold text-sm">내 진행 상황</span>
|
|
<span class="quick-action-desc text-xs text-text-secondary">스트릭 및 업적</span>
|
|
</div>
|
|
<svg class="quick-action-arrow w-5 h-5 stroke-text-muted fill-none"><use href="#icon-chevron-right"></use></svg>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="panel-card bg-surface-card rounded-[28px] shadow-md p-6">
|
|
<div class="panel-header flex items-center gap-3 mb-5">
|
|
<div class="panel-icon w-11 h-11 rounded-[12px] flex items-center justify-center bg-gradient-to-br from-primary to-primary-light">
|
|
<svg class="w-[22px] h-[22px] stroke-white fill-none"><use href="#icon-star"></use></svg>
|
|
</div>
|
|
<div>
|
|
<h3 class="panel-title text-lg font-display">업적 배지</h3>
|
|
<p class="panel-subtitle text-sm text-text-secondary">4/12 달성</p>
|
|
</div>
|
|
</div>
|
|
<div class="achievements-grid grid grid-cols-4 gap-3" id="achievements-grid"></div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Swipe Screen -->
|
|
<div id="swipe-screen" class="screen">
|
|
<button class="btn btn-icon btn-secondary back-btn fixed top-4 left-4 z-[100]" id="swipe-back">
|
|
<svg class="w-5 h-5 stroke-current fill-none"><use href="#icon-arrow-left"></use></svg>
|
|
</button>
|
|
|
|
<div class="swipe-container max-w-[400px] w-full flex flex-col items-center">
|
|
<div class="swipe-header text-center mb-6">
|
|
<h2 class="swipe-title text-xl mb-2 font-display">파일 정리하기</h2>
|
|
<p class="swipe-subtitle text-text-secondary">스와이프로 파일을 보관하거나 삭제하세요</p>
|
|
</div>
|
|
|
|
<div class="swipe-progress flex items-center gap-4 mb-8 w-full">
|
|
<div class="progress-bar flex-1 h-1.5 bg-surface-secondary rounded-full overflow-hidden">
|
|
<div class="progress-fill h-full bg-gradient-to-r from-primary to-secondary rounded-full transition-all duration-250" id="swipe-progress-fill" style="width: 60%"></div>
|
|
</div>
|
|
<span class="progress-text text-sm text-text-secondary whitespace-nowrap"><span id="swipe-current">4</span>/<span id="swipe-total">10</span></span>
|
|
</div>
|
|
|
|
<div class="card-stack relative w-full aspect-square max-h-[400px] mb-8" id="card-stack">
|
|
<div class="swipe-card absolute inset-0 bg-surface-card rounded-[28px] shadow-lg flex flex-col p-6 transition-transform duration-300 cursor-grab select-none overflow-hidden" id="current-card">
|
|
<span class="swipe-label delete absolute top-6 right-6 py-2 px-4 rounded-[12px] font-display font-bold text-xl uppercase bg-red-500/90 text-white rotate-12 opacity-0 transition-opacity duration-150 pointer-events-none">삭제</span>
|
|
<span class="swipe-label keep absolute top-6 left-6 py-2 px-4 rounded-[12px] font-display font-bold text-xl uppercase bg-emerald-500/90 text-white -rotate-12 opacity-0 transition-opacity duration-150 pointer-events-none">보관</span>
|
|
<div class="card-file-icon image w-20 h-20 mx-auto my-6 rounded-[20px] flex items-center justify-center bg-pink-500/15" id="card-icon">
|
|
<svg class="w-12 h-12 stroke-current fill-none stroke-[1.5]"><use href="#icon-photo"></use></svg>
|
|
</div>
|
|
<div class="card-info text-center flex-1 flex flex-col justify-center">
|
|
<h3 class="card-filename font-display text-xl font-semibold mb-2 break-words" id="card-filename">IMG_20240115_123456.jpg</h3>
|
|
<p class="card-meta text-text-secondary text-sm mb-4" id="card-meta">2024년 1월 15일 • 3.2 MB</p>
|
|
<div class="card-suggestion inline-flex items-center gap-2 bg-surface-secondary px-4 py-2 rounded-full text-sm text-text-secondary mx-auto" id="card-suggestion">
|
|
<svg class="w-4 h-4 stroke-primary fill-none"><use href="#icon-folder"></use></svg>
|
|
<span>📷 사진 폴더로 이동</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="swipe-actions flex justify-center gap-8 mb-6">
|
|
<button class="swipe-action delete w-[72px] h-[72px] rounded-full flex items-center justify-center cursor-pointer transition-all duration-500 bg-surface-card shadow-md hover:scale-110 active:scale-95 text-accent-danger border-none" id="swipe-delete">
|
|
<svg class="w-8 h-8 stroke-current fill-none stroke-2"><use href="#icon-trash"></use></svg>
|
|
</button>
|
|
<button class="swipe-action undo w-14 h-14 rounded-full flex items-center justify-center cursor-pointer transition-all duration-500 bg-surface-card shadow-md hover:scale-110 active:scale-95 text-accent-warn border-none hidden" id="swipe-undo">
|
|
<svg class="w-6 h-6 stroke-current fill-none stroke-2"><use href="#icon-undo"></use></svg>
|
|
</button>
|
|
<button class="swipe-action keep w-[72px] h-[72px] rounded-full flex items-center justify-center cursor-pointer transition-all duration-500 bg-surface-card shadow-md hover:scale-110 active:scale-95 text-accent border-none" id="swipe-keep">
|
|
<svg class="w-8 h-8 stroke-current fill-none stroke-2"><use href="#icon-arrow-right"></use></svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="swipe-hints flex justify-between w-full max-w-[300px] text-text-muted text-sm">
|
|
<div class="swipe-hint flex items-center gap-2">
|
|
<svg class="w-[18px] h-[18px] stroke-current fill-none"><use href="#icon-arrow-left"></use></svg>
|
|
<span>삭제</span>
|
|
</div>
|
|
<div class="swipe-hint flex items-center gap-2">
|
|
<span>보관</span>
|
|
<svg class="w-[18px] h-[18px] stroke-accent-warn fill-none stroke-2"><use href="#icon-arrow-right"></use></svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- AI Suggestion Screen -->
|
|
<div id="ai-suggestion" class="screen">
|
|
<button class="btn btn-icon btn-secondary back-btn fixed top-4 left-4 z-[100]" id="ai-back">
|
|
<svg class="w-5 h-5 stroke-current fill-none"><use href="#icon-arrow-left"></use></svg>
|
|
</button>
|
|
|
|
<div class="ai-container max-w-[900px] w-full">
|
|
<div class="ai-header text-center mb-8">
|
|
<h2 class="ai-title text-3xl mb-3 font-display">AI 구조 제안</h2>
|
|
<p class="ai-subtitle text-text-secondary text-lg">분석된 파일 패턴을 기반으로 최적화된 폴더 구조를 제안합니다</p>
|
|
</div>
|
|
|
|
<div class="comparison-view grid grid-cols-1 md:grid-cols-[1fr_auto_1fr] gap-6 items-start mb-8">
|
|
<div class="comparison-panel bg-surface-card rounded-[28px] shadow-md p-6">
|
|
<div class="comparison-header flex items-center gap-3 mb-5 pb-4 border-b border-surface-secondary">
|
|
<span class="comparison-badge before px-3 py-1 rounded-full text-xs font-bold uppercase bg-red-500/15 text-accent-danger">현재</span>
|
|
<span>현재 폴더 구조</span>
|
|
</div>
|
|
<div class="comparison-tree flex flex-col gap-2" id="before-tree"></div>
|
|
</div>
|
|
|
|
<div class="comparison-arrow hidden md:flex items-center justify-center pt-16">
|
|
<svg class="w-12 h-12 stroke-primary fill-none animate-pulse-slow"><use href="#icon-arrow-right"></use></svg>
|
|
</div>
|
|
|
|
<div class="comparison-panel bg-surface-card rounded-[28px] shadow-md p-6">
|
|
<div class="comparison-header flex items-center gap-3 mb-5 pb-4 border-b border-surface-secondary">
|
|
<span class="comparison-badge after px-3 py-1 rounded-full text-xs font-bold uppercase bg-emerald-500/15 text-accent">제안</span>
|
|
<span>정리된 구조</span>
|
|
</div>
|
|
<div class="comparison-tree flex flex-col gap-2" id="after-tree"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ai-actions flex justify-center gap-4">
|
|
<button class="btn btn-secondary" id="ai-cancel">
|
|
<svg class="w-5 h-5 stroke-current fill-none"><use href="#icon-x-mark"></use></svg>
|
|
<span>취소</span>
|
|
</button>
|
|
<button class="btn btn-primary" id="ai-apply">
|
|
<svg class="w-5 h-5 stroke-current fill-none"><use href="#icon-check"></use></svg>
|
|
<span>구조 적용하기</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Settings Screen -->
|
|
<div id="settings" class="screen">
|
|
<button class="btn btn-icon btn-secondary back-btn fixed top-4 left-4 z-[100]" id="settings-back">
|
|
<svg class="w-5 h-5 stroke-current fill-none"><use href="#icon-arrow-left"></use></svg>
|
|
</button>
|
|
|
|
<div class="settings-container max-w-[600px] w-full">
|
|
<div class="settings-header mb-8">
|
|
<h2 class="settings-title text-3xl mb-2 font-display">설정</h2>
|
|
<p class="settings-subtitle text-text-secondary">앱 환경 사용자 지정</p>
|
|
</div>
|
|
|
|
<div class="settings-section bg-surface-card rounded-[28px] shadow-md p-6 mb-5">
|
|
<h3 class="settings-section-title text-lg mb-5 pb-3 border-b border-surface-secondary font-display">알림</h3>
|
|
<div class="setting-row flex items-center justify-between py-4 border-b border-surface-secondary">
|
|
<div class="setting-info flex-1">
|
|
<div class="setting-name font-medium mb-1">정리 알림</div>
|
|
<div class="setting-desc text-sm text-text-secondary">매일 일정한 시간에 파일 정리를 안내합니다</div>
|
|
</div>
|
|
<div class="toggle active w-14 h-8 bg-surface-secondary rounded-full cursor-pointer transition-all duration-250 relative" id="toggle-notifications"></div>
|
|
</div>
|
|
<div class="setting-row flex items-center justify-between py-4 border-b-0">
|
|
<div class="setting-info flex-1">
|
|
<div class="setting-name font-medium mb-1">습관 형성 알림</div>
|
|
<div class="setting-desc text-sm text-text-secondary">정리 습관 형성을 돕는 동기를 부여합니다</div>
|
|
</div>
|
|
<div class="toggle w-14 h-8 bg-surface-secondary rounded-full cursor-pointer transition-all duration-250 relative" id="toggle-habits"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-section bg-surface-card rounded-[28px] shadow-md p-6 mb-5">
|
|
<h3 class="settings-section-title text-lg mb-5 pb-3 border-b border-surface-secondary font-display">정리 습관</h3>
|
|
<div class="setting-row flex items-center justify-between py-4 border-b border-surface-secondary">
|
|
<div class="setting-info flex-1">
|
|
<div class="setting-name font-medium mb-1">자동 정리</div>
|
|
<div class="setting-desc text-sm text-text-secondary">자동으로 파일을 제안된 구조로 정리합니다</div>
|
|
</div>
|
|
<div class="toggle w-14 h-8 bg-surface-secondary rounded-full cursor-pointer transition-all duration-250 relative" id="toggle-auto-organize"></div>
|
|
</div>
|
|
<div class="setting-row flex items-center justify-between py-4 border-b-0">
|
|
<div class="setting-info flex-1">
|
|
<div class="setting-name font-medium mb-1">삭제 전 확인</div>
|
|
<div class="setting-desc text-sm text-text-secondary">파일 삭제 전에 확인 메시지를 표시합니다</div>
|
|
</div>
|
|
<div class="toggle active w-14 h-8 bg-surface-secondary rounded-full cursor-pointer transition-all duration-250 relative" id="toggle-confirm-delete"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-section bg-surface-card rounded-[28px] shadow-md p-6 mb-5">
|
|
<h3 class="settings-section-title text-lg mb-5 pb-3 border-b border-surface-secondary font-display">테마</h3>
|
|
<div class="setting-row flex items-center justify-between py-4 border-b-0">
|
|
<div class="setting-info flex-1">
|
|
<div class="setting-name font-medium mb-1">외관</div>
|
|
<div class="setting-desc text-sm text-text-secondary">라이트 또는 다크 모드를 선택하세요</div>
|
|
</div>
|
|
<div class="theme-selector flex gap-3">
|
|
<div class="theme-option light active w-12 h-12 rounded-[12px] cursor-pointer border-[3px] border-transparent transition-all duration-250 hover:scale-105 flex items-center justify-center bg-gradient-to-br from-[#faf9fb] to-[#f3f2f7]" data-theme="light">
|
|
<svg class="w-5 h-5 stroke-text-primary fill-none"><use href="#icon-sun"></use></svg>
|
|
</div>
|
|
<div class="theme-option dark w-12 h-12 rounded-[12px] cursor-pointer border-[3px] border-transparent transition-all duration-250 hover:scale-105 flex items-center justify-center bg-gradient-to-br from-[#0f0e17] to-[#252336]" data-theme="dark">
|
|
<svg class="w-5 h-5 stroke-text-primary fill-none"><use href="#icon-moon"></use></svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-section bg-surface-card rounded-[28px] shadow-md p-6">
|
|
<h3 class="settings-section-title text-lg mb-5 pb-3 border-b border-surface-secondary font-display">데이터</h3>
|
|
<div class="setting-row flex items-center justify-between py-4 border-b border-surface-secondary">
|
|
<div class="setting-info flex-1">
|
|
<div class="setting-name font-medium mb-1">데이터 내보내기</div>
|
|
<div class="setting-desc text-sm text-text-secondary">정리된 파일 구조를 JSON으로 내보냅니다</div>
|
|
</div>
|
|
<button class="btn btn-secondary" id="export-data">
|
|
<svg class="w-5 h-5 stroke-current fill-none"><use href="#icon-download"></use></svg>
|
|
<span>내보내기</span>
|
|
</button>
|
|
</div>
|
|
<div class="setting-row flex items-center justify-between py-4 border-b-0">
|
|
<div class="setting-info flex-1">
|
|
<div class="setting-name font-medium mb-1">데이터 초기화</div>
|
|
<div class="setting-desc text-sm text-text-secondary">모든 데이터를 초기 상태로 되돌립니다</div>
|
|
</div>
|
|
<button class="btn btn-secondary text-accent-danger" id="reset-data">
|
|
<svg class="w-5 h-5 stroke-current fill-none"><use href="#icon-trash"></use></svg>
|
|
<span>초기화</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Success Modal -->
|
|
<div class="modal-overlay fixed inset-0 bg-black/50 flex items-center justify-center z-[1000] opacity-0 invisible transition-all duration-250" id="success-modal">
|
|
<div class="modal bg-surface-card rounded-[28px] p-8 max-w-[400px] w-[90%] text-center scale-90 transition-transform duration-500" style="transform: scale(0.9)">
|
|
<div class="modal-icon w-20 h-20 mx-auto mb-5 bg-gradient-to-br from-accent to-emerald-500 rounded-full flex items-center justify-center">
|
|
<svg class="w-10 h-10 stroke-white fill-none"><use href="#icon-check"></use></svg>
|
|
</div>
|
|
<h3 class="modal-title text-2xl mb-3 font-display">정리 완료!</h3>
|
|
<p class="modal-desc text-text-secondary mb-6">파일 정리가 성공적으로 완료되었습니다.</p>
|
|
<button class="btn btn-primary" id="modal-close">
|
|
<span>계속하기</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Toast -->
|
|
<div class="toast fixed bottom-8 left-1/2 -translate-x-1/2 translate-y-[100px] bg-surface-card px-6 py-4 rounded-full shadow-lg flex items-center gap-3 z-[500] transition-transform duration-500" id="toast">
|
|
<div class="toast-icon w-8 h-8 rounded-full flex items-center justify-center bg-amber-500/15 text-accent-warn">
|
|
<svg class="w-[18px] h-[18px] stroke-current fill-none text-orange-500"><use href="#icon-fire"></use></svg>
|
|
</div>
|
|
<span class="toast-message font-medium" id="toast-message">7일 스트릭 달성!</span>
|
|
</div>
|
|
|
|
<script>
|
|
const state = {
|
|
currentScreen: 'onboarding',
|
|
onboardingStep: 1,
|
|
streak: parseInt(localStorage.getItem('chackly_streak') || '7'),
|
|
filesOrganized: parseInt(localStorage.getItem('chackly_files_organized') || '248'),
|
|
foldersManaged: parseInt(localStorage.getItem('chackly_folders') || '12'),
|
|
swipeIndex: 0,
|
|
swipeHistory: [],
|
|
theme: localStorage.getItem('chackly_theme') || 'light',
|
|
settings: JSON.parse(localStorage.getItem('chackly_settings') || '{"notifications":true,"habits":false,"autoOrganize":false,"confirmDelete":true}')
|
|
};
|
|
|
|
const mockFiles = [
|
|
{ name: 'IMG_20240115_123456.jpg', type: 'image', size: '3.2 MB', date: '2024년 1월 15일', folder: '📷 사진' },
|
|
{ name: 'report_Q4_2023.pdf', type: 'pdf', size: '1.8 MB', date: '2024년 1월 10일', folder: '📄 문서' },
|
|
{ name: 'vacation_video.mp4', type: 'video', size: '156 MB', date: '2024년 1월 8일', folder: '🎬 영상' },
|
|
{ name: 'presentation.pptx', type: 'doc', size: '5.4 MB', date: '2024년 1월 5일', folder: '📄 문서' },
|
|
{ name: 'screenshot_2024.png', type: 'image', size: '890 KB', date: '2024년 1월 3일', folder: '📷 사진' },
|
|
{ name: 'meeting_notes.docx', type: 'doc', size: '245 KB', date: '2023년 12월 28일', folder: '📄 문서' },
|
|
{ name: 'family_photo.jpg', type: 'image', size: '4.1 MB', date: '2023년 12월 25일', folder: '📷 사진' },
|
|
{ name: 'project_files.zip', type: 'archive', size: '45 MB', date: '2023년 12월 20일', folder: '📦 압축' },
|
|
{ name: 'music_playlist.m3u', type: 'doc', size: '12 KB', date: '2023년 12월 15일', folder: '🎵 음악' },
|
|
{ name: 'budget_2024.xlsx', type: 'doc', size: '567 KB', date: '2023년 12월 10일', folder: '📊 스프레드시트' }
|
|
];
|
|
|
|
const fileTree = [
|
|
{ name: '📁 문서', type: 'folder', children: [
|
|
{ name: '📄 report_Q4_2023.pdf', type: 'pdf', meta: '1.8 MB' },
|
|
{ name: '📄 presentation.pptx', type: 'ppt', meta: '5.4 MB' },
|
|
{ name: '📄 meeting_notes.docx', type: 'doc', meta: '245 KB' }
|
|
]},
|
|
{ name: '📁 사진', type: 'folder', children: [
|
|
{ name: '🖼️ IMG_20240115.jpg', type: 'image', meta: '3.2 MB' },
|
|
{ name: '🖼️ screenshot_2024.png', type: 'image', meta: '890 KB' },
|
|
{ name: '🖼️ family_photo.jpg', type: 'image', meta: '4.1 MB' }
|
|
]},
|
|
{ name: '📁 영상', type: 'folder', children: [
|
|
{ name: '🎬 vacation_video.mp4', type: 'video', meta: '156 MB' }
|
|
]},
|
|
{ name: '📁 압축', type: 'folder', children: [
|
|
{ name: '📦 project_files.zip', type: 'archive', meta: '45 MB' }
|
|
]}
|
|
];
|
|
|
|
const suggestions = [
|
|
{ name: '📷 사진 → 2024', detail: '2개 파일 이동', selected: false },
|
|
{ name: '📄 문서 → quarterly', detail: '3개 파일 이동', selected: true },
|
|
{ name: '📦 압축 → 보관', detail: '1개 파일 이동', selected: false }
|
|
];
|
|
|
|
const achievements = [
|
|
{ name: '첫 정리', icon: '🏆', color: 'gold', unlocked: true },
|
|
{ name: '7일 스트릭', icon: '🔥', color: 'gold', unlocked: true },
|
|
{ name: '파일 마스터', icon: '📁', color: 'silver', unlocked: true },
|
|
{ name: '정리의 달인', icon: '⭐', color: 'silver', unlocked: true },
|
|
{ name: '30일 스트릭', icon: '💎', color: 'gold', unlocked: false },
|
|
{ name: 'AI 활용자', icon: '🤖', color: 'bronze', unlocked: false },
|
|
{ name: '조직력왕', icon: '👑', color: 'silver', unlocked: false },
|
|
{ name: '창의命名', icon: '💡', color: 'bronze', unlocked: false }
|
|
];
|
|
|
|
function showScreen(screenId) {
|
|
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
|
|
document.getElementById(screenId).classList.add('active');
|
|
state.currentScreen = screenId;
|
|
}
|
|
|
|
function updateOnboardingStep(step) {
|
|
document.querySelectorAll('.step-dot').forEach((dot, i) => {
|
|
const isActive = i + 1 === step;
|
|
dot.classList.toggle('active', isActive);
|
|
dot.classList.toggle('bg-primary', isActive);
|
|
dot.classList.toggle('bg-text-muted', !isActive);
|
|
dot.style.width = isActive ? '32px' : '8px';
|
|
});
|
|
document.querySelectorAll('.onboarding-step').forEach(s => {
|
|
const isActive = parseInt(s.dataset.step) === step;
|
|
s.classList.toggle('active', isActive);
|
|
s.classList.toggle('hidden', !isActive);
|
|
});
|
|
state.onboardingStep = step;
|
|
}
|
|
|
|
function renderFileTree() {
|
|
const container = document.getElementById('file-tree');
|
|
container.innerHTML = fileTree.map(item => `
|
|
<div class="tree-item folder flex items-center gap-3 p-3 bg-accent/10 rounded-[12px] cursor-pointer hover:bg-overlay hover:translate-x-1 transition-all duration-150">
|
|
<div class="tree-icon folder-icon w-8 h-8 rounded-[8px] flex items-center justify-center flex-shrink-0 bg-primary/15 text-primary">
|
|
<svg class="w-[18px] h-[18px] stroke-current fill-none stroke-2"><use href="#icon-folder"></use></svg>
|
|
</div>
|
|
<div class="tree-item-info flex-1 min-w-0">
|
|
<div class="tree-item-name font-medium truncate">${item.name}</div>
|
|
<div class="tree-item-meta text-xs text-text-muted">${item.children.length}개 항목</div>
|
|
</div>
|
|
</div>
|
|
<div class="tree-children ml-8 flex flex-col gap-2">
|
|
${item.children.map(child => `
|
|
<div class="tree-item flex items-center gap-3 p-3 bg-surface-secondary rounded-[12px] cursor-pointer hover:bg-overlay hover:translate-x-1 transition-all duration-150">
|
|
<div class="tree-icon ${child.type === 'image' ? 'image-icon' : child.type === 'video' ? 'image-icon' : 'doc-icon'} w-8 h-8 rounded-[8px] flex items-center justify-center flex-shrink-0 ${child.type === 'image' ? 'bg-pink-500/15 text-secondary' : child.type === 'video' ? 'bg-purple-500/15 text-purple-500' : 'bg-amber-500/15 text-accent-warn'}">
|
|
<svg class="w-[18px] h-[18px] stroke-current fill-none stroke-2"><use href="#icon-document"></use></svg>
|
|
</div>
|
|
<div class="tree-item-info flex-1 min-w-0">
|
|
<div class="tree-item-name font-medium truncate">${child.name}</div>
|
|
<div class="tree-item-meta text-xs text-text-muted">${child.meta}</div>
|
|
</div>
|
|
</div>
|
|
`).join('')}
|
|
</div>
|
|
`).join('');
|
|
}
|
|
|
|
function renderSuggestions() {
|
|
const container = document.getElementById('suggestion-list');
|
|
container.innerHTML = suggestions.map((s, i) => `
|
|
<div class="suggestion-item flex items-center gap-3 p-3 bg-surface-secondary rounded-[12px] cursor-pointer border-2 border-transparent transition-all duration-150 ${s.selected ? 'bg-primary/10 border-primary' : 'hover:bg-overlay hover:border-primary-light'}" data-index="${i}">
|
|
<div class="suggestion-checkbox w-6 h-6 border-2 ${s.selected ? 'bg-primary border-primary' : 'border-text-muted'} rounded-[8px] flex items-center justify-center flex-shrink-0 transition-all duration-150">
|
|
<svg class="w-3.5 h-3.5 stroke-white fill-none ${s.selected ? 'opacity-100' : 'opacity-0'} transition-opacity duration-150"><use href="#icon-check"></use></svg>
|
|
</div>
|
|
<div class="suggestion-content flex-1">
|
|
<div class="suggestion-name font-medium mb-0.5">${s.name}</div>
|
|
<div class="suggestion-detail text-sm text-text-secondary">${s.detail}</div>
|
|
</div>
|
|
<svg class="suggestion-arrow w-5 h-5 stroke-text-muted fill-none"><use href="#icon-chevron-right"></use></svg>
|
|
</div>
|
|
`).join('');
|
|
|
|
container.querySelectorAll('.suggestion-item').forEach(item => {
|
|
item.addEventListener('click', () => {
|
|
const idx = parseInt(item.dataset.index);
|
|
suggestions[idx].selected = !suggestions[idx].selected;
|
|
renderSuggestions();
|
|
});
|
|
});
|
|
}
|
|
|
|
function renderAchievements() {
|
|
const container = document.getElementById('achievements-grid');
|
|
container.innerHTML = achievements.map(a => `
|
|
<div class="achievement aspect-square bg-surface-secondary rounded-[12px] flex flex-col items-center justify-center gap-1 p-2 transition-all duration-250 cursor-pointer hover:scale-105 ${a.unlocked ? '' : 'opacity-40 grayscale'}">
|
|
<div class="achievement-icon w-9 h-9 rounded-[8px] flex items-center justify-center ${a.unlocked ? a.color === 'gold' ? 'bg-gradient-to-br from-amber-400 to-amber-600 text-white' : a.color === 'silver' ? 'bg-gradient-to-br from-gray-300 to-gray-500 text-white' : 'bg-gradient-to-br from-amber-700 to-amber-900 text-white' : 'bg-overlay text-primary'}">
|
|
<span class="text-lg">${a.icon}</span>
|
|
</div>
|
|
<div class="achievement-name text-[10px] text-center text-text-secondary">${a.name}</div>
|
|
<div class="badge-tooltip absolute -top-8 left-1/2 -translate-x-1/2 bg-text-primary text-surface-card px-2 py-1 rounded-[8px] text-xs whitespace-nowrap opacity-0 invisible transition-all duration-150">${a.name}</div>
|
|
</div>
|
|
`).join('');
|
|
}
|
|
|
|
function updateSwipeCard() {
|
|
if (state.swipeIndex >= mockFiles.length) return;
|
|
const file = mockFiles[state.swipeIndex];
|
|
document.getElementById('card-filename').textContent = file.name;
|
|
document.getElementById('card-meta').textContent = `${file.date} • ${file.size}`;
|
|
document.getElementById('card-suggestion').innerHTML = `<svg class="w-4 h-4 stroke-primary fill-none"><use href="#icon-folder"></use></svg><span>${file.folder}로 이동</span>`;
|
|
const iconEl = document.getElementById('card-icon');
|
|
iconEl.className = `card-file-icon ${file.type === 'image' ? 'image' : file.type === 'video' ? 'video' : file.type === 'pdf' ? 'pdf' : 'doc'} w-20 h-20 mx-auto my-6 rounded-[20px] flex items-center justify-center ${file.type === 'image' ? 'bg-pink-500/15 text-secondary' : file.type === 'video' ? 'bg-purple-500/15 text-purple-500' : file.type === 'pdf' ? 'bg-amber-500/15 text-accent-warn' : 'bg-primary/15 text-primary'}`;
|
|
document.getElementById('swipe-progress-fill').style.width = `${((state.swipeIndex + 1) / mockFiles.length) * 100}%`;
|
|
document.getElementById('swipe-current').textContent = state.swipeIndex + 1;
|
|
document.getElementById('swipe-total').textContent = mockFiles.length;
|
|
}
|
|
|
|
document.getElementById('onboarding-next').addEventListener('click', () => {
|
|
if (state.onboardingStep < 3) {
|
|
updateOnboardingStep(state.onboardingStep + 1);
|
|
} else {
|
|
showScreen('dashboard');
|
|
}
|
|
});
|
|
|
|
document.getElementById('settings-btn').addEventListener('click', () => showScreen('settings'));
|
|
document.getElementById('settings-back').addEventListener('click', () => showScreen('dashboard'));
|
|
document.getElementById('swipe-back').addEventListener('click', () => showScreen('dashboard'));
|
|
document.getElementById('ai-back').addEventListener('click', () => showScreen('dashboard'));
|
|
document.getElementById('apply-suggestions').addEventListener('click', () => showScreen('ai-suggestion'));
|
|
|
|
document.getElementById('ai-cancel').addEventListener('click', () => showScreen('dashboard'));
|
|
document.getElementById('ai-apply').addEventListener('click', () => {
|
|
showScreen('dashboard');
|
|
document.getElementById('success-modal').classList.add('active');
|
|
document.querySelector('.modal').style.transform = 'scale(1)';
|
|
});
|
|
|
|
document.getElementById('modal-close').addEventListener('click', () => {
|
|
document.getElementById('success-modal').classList.remove('active');
|
|
});
|
|
|
|
document.querySelectorAll('.toggle').forEach(toggle => {
|
|
toggle.addEventListener('click', () => {
|
|
toggle.classList.toggle('active');
|
|
toggle.style.background = toggle.classList.contains('active') ? '#3b82f6' : '';
|
|
toggle.querySelector('::after') && (toggle.style.setProperty('--after-transform', toggle.classList.contains('active') ? 'translateX(24px)' : ''));
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('.theme-option').forEach(option => {
|
|
option.addEventListener('click', () => {
|
|
document.querySelectorAll('.theme-option').forEach(o => o.classList.remove('active'));
|
|
option.classList.add('active');
|
|
document.body.setAttribute('data-theme', option.dataset.theme);
|
|
localStorage.setItem('chackly_theme', option.dataset.theme);
|
|
});
|
|
});
|
|
|
|
let touchStartX = 0;
|
|
const card = document.getElementById('current-card');
|
|
|
|
card.addEventListener('touchstart', e => {
|
|
touchStartX = e.touches[0].clientX;
|
|
card.classList.add('dragging');
|
|
});
|
|
|
|
card.addEventListener('touchmove', e => {
|
|
const diff = e.touches[0].clientX - touchStartX;
|
|
card.style.transform = `translateX(${diff}px) rotate(${diff * 0.05}deg)`;
|
|
card.classList.toggle('swiping-left', diff < -50);
|
|
card.classList.toggle('swiping-right', diff > 50);
|
|
});
|
|
|
|
card.addEventListener('touchend', e => {
|
|
const diff = e.changedTouches[0].clientX - touchStartX;
|
|
card.classList.remove('dragging', 'swiping-left', 'swiping-right');
|
|
if (Math.abs(diff) > 100) {
|
|
state.swipeHistory.push({ file: mockFiles[state.swipeIndex], action: diff > 0 ? 'keep' : 'delete' });
|
|
state.swipeIndex++;
|
|
updateSwipeCard();
|
|
} else {
|
|
card.style.transform = '';
|
|
}
|
|
});
|
|
|
|
document.getElementById('swipe-delete').addEventListener('click', () => {
|
|
state.swipeHistory.push({ file: mockFiles[state.swipeIndex], action: 'delete' });
|
|
state.swipeIndex++;
|
|
updateSwipeCard();
|
|
});
|
|
|
|
document.getElementById('swipe-keep').addEventListener('click', () => {
|
|
state.swipeHistory.push({ file: mockFiles[state.swipeIndex], action: 'keep' });
|
|
state.swipeIndex++;
|
|
updateSwipeCard();
|
|
});
|
|
|
|
document.getElementById('swipe-undo').addEventListener('click', () => {
|
|
if (state.swipeHistory.length > 0) {
|
|
state.swipeIndex--;
|
|
state.swipeHistory.pop();
|
|
updateSwipeCard();
|
|
}
|
|
});
|
|
|
|
renderFileTree();
|
|
renderSuggestions();
|
|
renderAchievements();
|
|
updateSwipeCard();
|
|
</script>
|
|
</body>
|
|
</html> |