Files
chakmate/index.html
yenru0 3735240eed refactor: apply Tailwind CSS and Heroicons to all HTML files
- Replace custom CSS with Tailwind utility classes
- Convert all inline SVGs to Heroicons sprite system
- Add consistent Tailwind config with design tokens
- Improve responsive layout for onboarding screen
2026-05-18 18:04:47 +09:00

932 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="M12 23c-3.866 0-7-3.134-7-7 0-2.5 1.5-4.5 3-6 .5-.5 1.5-2 1.5-3.5 0 1.5.5 2 1.5 2.5 0-3 2-6.5 4-8.5.5-.5 1.5-.5 2 0 1.5 2 3 5 3 8.5 0 1.5.5 2.5 1.5 3 1.5 1.5 3 3.5 3 6 0 3.866-3.134 7-7 7z"/>
</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] fill-current"><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] fill-current stroke-white"><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] fill-current 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>