refactor: restructure project with shared state and public assets

This commit is contained in:
2026-05-21 20:44:12 +09:00
parent c58b5ab24d
commit 1ef6cb1379
19 changed files with 241 additions and 180 deletions

20
package-lock.json generated
View File

@@ -7,6 +7,10 @@
"": {
"name": "chakmate",
"version": "1.0.0",
"dependencies": {
"@fontsource/noto-sans-kr": "^5.2.9",
"@fontsource/outfit": "^5.2.8"
},
"devDependencies": {
"@tauri-apps/cli": "^2.0.0",
"autoprefixer": "^10.4.20",
@@ -395,6 +399,22 @@
"node": ">=12"
}
},
"node_modules/@fontsource/noto-sans-kr": {
"version": "5.2.9",
"resolved": "https://registry.npmjs.org/@fontsource/noto-sans-kr/-/noto-sans-kr-5.2.9.tgz",
"integrity": "sha512-pbF8F0rUzKkDmnk/KYGAbxjgW4TrIHdFKnV6OQ+kUC9ELCn5utrAURcEgMqq3J9SRX+FvjOz+aBCmfcC8/r7cw==",
"funding": {
"url": "https://github.com/sponsors/ayuhito"
}
},
"node_modules/@fontsource/outfit": {
"version": "5.2.8",
"resolved": "https://registry.npmjs.org/@fontsource/outfit/-/outfit-5.2.8.tgz",
"integrity": "sha512-rXC6g0MqD7cOBjht0bMqc43qM6lRqDLML9KXsmg9uykz0wLQhy8Z/ajrMG6iyoT3NJR+MYgU+OEHp7uHoTb+Yw==",
"funding": {
"url": "https://github.com/sponsors/ayuhito"
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",

View File

@@ -9,7 +9,10 @@
"preview": "vite preview",
"tauri": "tauri"
},
"dependencies": {},
"dependencies": {
"@fontsource/noto-sans-kr": "^5.2.9",
"@fontsource/outfit": "^5.2.8"
},
"devDependencies": {
"@tauri-apps/cli": "^2.0.0",
"autoprefixer": "^10.4.20",
@@ -17,4 +20,4 @@
"tailwindcss": "^3.4.17",
"vite": "^5.4.0"
}
}
}

View File

@@ -1,89 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 6.2 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -4,9 +4,6 @@
<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">
<link rel="stylesheet" href="./styles/main.css">
<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">
@@ -455,6 +452,6 @@
<span class="toast-message font-medium" id="toast-message">7일 스트릭 달성!</span>
</div>
<script type="module" src="./scripts/main.js"></script>
<script type="module" src="./scripts/shared/state.js"></script>
</body>
</html>

View File

@@ -4,9 +4,6 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI 분류 - 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">
<link rel="stylesheet" href="../styles/main.css">
<!-- Heroicons SVG Sprite -->
<svg xmlns="http://www.w3.org/2000/svg" class="hidden">
@@ -112,7 +109,7 @@
<div class="max-w-[1200px] w-full mx-auto p-6">
<!-- Back Header -->
<div class="flex items-center gap-4 mb-8">
<a href="index.html" class="inline-flex items-center gap-2 text-text-secondary font-medium transition-colors duration-150 hover:text-primary hover:bg-accent/10 rounded-xl px-3 py-2">
<a href="scene_dashboard.html" class="inline-flex items-center gap-2 text-text-secondary font-medium transition-colors duration-150 hover:text-primary hover:bg-accent/10 rounded-xl px-3 py-2">
<svg class="w-5 h-5"><use href="#icon-arrow-left"></use></svg>
<span>대시보드로</span>
</a>

View File

@@ -4,9 +4,6 @@
<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">
<link rel="stylesheet" href="../styles/main.css">
<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">
@@ -100,21 +97,22 @@
<nav class="fixed bottom-0 left-0 right-0 bg-surface-card border-t border-surface-secondary z-[100]">
<div class="max-w-[600px] mx-auto flex justify-around py-3">
<button class="nav-btn flex flex-col items-center gap-1 px-6 py-2 rounded-2xl transition-all duration-250 active bg-primary/10 text-primary" id="nav-dashboard">
<span class="nav-btn flex flex-col items-center gap-1 px-6 py-2 rounded-2xl transition-all duration-250 active bg-primary/10 text-primary">
<svg class="w-6 h-6 stroke-current fill-none"><use href="#icon-layers"></use></svg>
<span class="text-xs font-medium"></span>
</button>
<button class="nav-btn flex flex-col items-center gap-1 px-6 py-2 rounded-2xl transition-all duration-250 text-text-muted" id="nav-swipe" onclick="window.location.href='scene_swipe.html'">
</span>
<a href="scene_swipe.html" class="nav-btn flex flex-col items-center gap-1 px-6 py-2 rounded-2xl transition-all duration-250 text-text-muted">
<svg class="w-6 h-6 stroke-current fill-none"><use href="#icon-bolt"></use></svg>
<span class="text-xs font-medium">스와이프</span>
</button>
<button class="nav-btn flex flex-col items-center gap-1 px-6 py-2 rounded-2xl transition-all duration-250 text-text-muted" id="nav-settings" onclick="window.location.href='scene_settings.html'">
</a>
<a href="scene_settings.html" class="nav-btn flex flex-col items-center gap-1 px-6 py-2 rounded-2xl transition-all duration-250 text-text-muted">
<svg class="w-6 h-6 stroke-current fill-none"><use href="#icon-cog"></use></svg>
<span class="text-xs font-medium">설정</span>
</button>
</a>
</div>
</nav>
<script type="module" src="../scripts/shared/state.js"></script>
<script type="module" src="../scripts/dashboard.js"></script>
</body>
</html>

View File

@@ -300,6 +300,7 @@
<div class="fixed top-0 left-0 w-full h-full pointer-events-none z-[1000] overflow-hidden" id="confettiContainer"></div>
<script type="module" src="../scripts/shared/state.js"></script>
<script type="module" src="../scripts/gamification.js"></script>
</body>
</html>

View File

@@ -4,9 +4,6 @@
<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">
<link rel="stylesheet" href="../styles/main.css">
<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">

View File

@@ -4,9 +4,6 @@
<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">
<link rel="stylesheet" href="../styles/main.css">
<svg xmlns="http://www.w3.org/2000/svg" style="display: none">
<symbol id="icon-x-mark" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -34,10 +31,10 @@
</head>
<body class="font-sans bg-surface-primary text-text-primary min-h-screen antialiased overflow-x-hidden">
<header class="flex items-center justify-between p-5 bg-surface-card rounded-b-3xl shadow-[0_4px_20px_rgba(30,27,46,0.08)]">
<button class="flex items-center gap-2 px-4 py-2 rounded-full text-text-secondary hover:bg-surface-secondary transition-colors" onclick="window.location.href='scene_dashboard.html'">
<a href="scene_dashboard.html" class="flex items-center gap-2 px-4 py-2 rounded-full text-text-secondary hover:bg-surface-secondary transition-colors">
<svg class="w-5 h-5"><use href="#icon-home"></use></svg>
<span class="text-sm font-medium">홈으로</span>
</button>
</a>
<h1 class="font-display text-lg font-semibold text-text-primary">설정</h1>
<div class="w-[80px]"></div>
</header>
@@ -121,6 +118,7 @@
</div>
</div>
<script type="module" src="../scripts/shared/state.js"></script>
<script type="module" src="../scripts/settings.js"></script>
</body>
</html>

View File

@@ -4,9 +4,6 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<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">
<link rel="stylesheet" href="../styles/main.css">
</head>
<body class="font-sans bg-surface-primary text-text-primary min-h-screen antialiased">
@@ -27,10 +24,10 @@
</svg>
<header class="flex items-center justify-between p-5 bg-surface-card rounded-b-3xl shadow-[0_4px_20px_rgba(30,27,46,0.08)]">
<button class="flex items-center gap-2 px-4 py-2 rounded-full text-text-secondary hover:bg-surface-secondary transition-colors" onclick="window.location.href='scene_dashboard.html'">
<a href="scene_dashboard.html" class="flex items-center gap-2 px-4 py-2 rounded-full text-text-secondary hover:bg-surface-secondary transition-colors">
<svg class="w-5 h-5"><use href="#icon-home"></use></svg>
<span class="text-sm font-medium"></span>
</button>
</a>
<h1 class="font-display text-lg font-semibold text-text-primary">스와이프 모드</h1>
<button class="flex items-center gap-2 px-5 py-3 bg-gradient-to-r from-primary to-primary-dark rounded-full text-white text-sm font-semibold shadow-md transition-all duration-250 hover:-translate-y-0.5 hover:shadow-lg disabled:opacity-40 disabled:cursor-not-allowed disabled:transform-none" id="undoBtn" disabled>
<svg class="w-4 h-4"><use href="#icon-arrow-uturn-left"></use></svg>

View File

@@ -4,9 +4,6 @@
<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">
<!-- Heroicons SVG Sprite -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none; width: 0; height: 0;">
<symbol id="icon-arrow-left" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -85,11 +82,11 @@
<h1 class="header-title">구조 제안</h1>
</div>
<div class="header-right">
<button class="back-btn" onclick="window.location.href='index.html'" aria-label="Go back">
<a href="scene_dashboard.html" class="back-btn" aria-label="Go back">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<use href="#icon-arrow-left"></use>
</svg>
</button>
</a>
</div>
</header>

56
src/public/logo.svg Normal file
View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="500"
height="500"
viewBox="0 0 500 500"
version="1.1"
id="svg4"
sodipodi:docname="logo.svg"
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs4" />
<sodipodi:namedview
id="namedview4"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.2099419"
inkscape:cx="238.4412"
inkscape:cy="279.35225"
inkscape:window-width="1235"
inkscape:window-height="975"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<title
id="title1">Puzzle CI Logo</title>
<path
d="m 144.04047,151.41 -1.5919,0.79 -2.1855,1.46 -2.06408,2.15 -1.32209,2.44 -0.75548,2.73 L 136,163.62 v 2.59 2.59 2.63 2.74 2.64 2.58 2.59 2.64 2.73 2.64 2.73 2.64 2.59 2.59 2.63 2.74 2.63 2.59 2.59 2.64 2.73 2.64 2.73 2.64 2.59 2.58 2.64 2.73 2.64 2.59 2.59 2.63 2.74 2.64 2.73 l 0.74199,1.81 1.457,0.97 h 2.3204 2.37437 2.45531 2.37437 2.3339 2.33389 2.37437 2.45531 2.37437 2.45531 2.37437 l 2.33389,0.34 1.44351,1.27 0.4452,2.15 -0.4452,2.74 -0.70152,2.63 -0.60708,2.59 -0.5801,2.59 -0.31029,2.64 0.17538,2.73 0.5801,2.64 1.01181,2.73 1.3086,2.64 1.76728,2.59 2.19899,2.1 2.36088,1.66 2.4688,0.97 2.37437,0.49 2.3204,0.15 2.3339,-0.15 2.37437,-0.49 2.45531,-1.17 2.37437,-1.61 2.19899,-2.3 1.75379,-2.44 1.32209,-2.58 0.8769,-2.59 0.44519,-2.64 v -2.73 l -0.31028,-2.64 -0.43171,-2.59 -0.5801,-2.59 -0.60708,-2.63 -0.4452,-2.74 0.62058,-2.15 1.57841,-1.27 2.37437,-0.34 h 2.32041 2.33389 2.37437 2.45531 2.37437 2.33389 2.3339 2.36088 2.4688 2.37437 2.45531 l 2.06408,-0.49 1.32209,-1.31 0.4452,-2.25 v -2.64 -2.73 -2.64 -2.59 -2.58 -2.64 -2.73 -2.64 -2.74 -2.63 -2.59 -2.59 l -0.75549,-1.8 -1.57841,-0.64 -2.37437,0.49 -2.33389,0.78 -2.32041,0.68 -2.37437,0.49 -2.4688,0.15 -2.37437,-0.15 -2.45531,-0.68 -2.37437,-0.98 -2.3204,-1.61 -2.3339,-2.1 -1.92917,-2.64 -1.59191,-2.73 -0.74199,-2.64 -0.56661,-2.59 v -2.58 l 0.12142,-2.64 0.75548,-2.73 1.01181,-2.64 1.75379,-2.74 2.06408,-2.44 2.3339,-1.95 2.3204,-1.32 2.37437,-0.83 2.4688,-0.49 2.37437,-0.14 2.3204,0.14 2.3339,0.49 2.37437,0.69 2.45531,0.78 2.06408,0.19 1.32209,-0.97 0.4452,-2.15 v -2.59 -2.59 -2.64 -2.73 -2.64 -2.58 -2.59 -2.64 -2.73 -2.64 -2.73 -2.64 l -0.75549,-1.95 -1.57841,-0.98 -2.37437,-0.15 h -2.45531 -2.37437 -2.33389 -2.3339 -2.37437 -2.45531 -2.37437 -2.45531 -2.37437 -2.33389 -2.32041 -2.37436 -2.46881 -2.37436 -2.32041 -2.33389 -2.37437 -2.45531 -2.37437 -2.45531 -2.37437 -2.3339 -2.33389 -2.37437 -2.45531 -2.37437 -2.3339 -2.3204 -2.37437 -2.45531 -2.37437 -2.4688 -2.37437 -1.75379 z"
fill="#6e9dea"
id="path1"
style="stroke-width:1.1615" />
<path
d="m 290.10456,98.68 -0.4317,1.76 -0.62058,2.63 -0.70152,2.59 -0.62057,2.44 -0.70152,2.59 -0.60708,2.64 -0.71501,2.59 -0.60708,2.44 -0.70152,2.59 -0.62057,2.63 -0.56661,2.59 -0.5801,2.44 -0.8769,2.59 -1.49747,1.32 h -1.8887 l -2.1855,-1.47 -2.3339,-1.61 -2.37436,-1.46 -2.3339,-1.17 -2.1855,-0.64 -2.33389,-0.15 -2.37437,0.15 -2.3339,0.49 -2.3204,0.83 -2.37437,1.27 -2.33389,1.95 -1.88871,2.3 -1.61888,2.58 -1.01181,2.64 -0.75548,2.59 -0.12141,2.44 v 2.59 l 0.4317,2.63 0.70152,2.59 1.18718,2.44 1.7538,2.45 2.07757,2.29 2.3204,1.76 2.19899,1.17 2.3339,0.63 2.37436,0.35 2.32041,0.14 h 2.19899 2.33389 l 2.37437,0.49 1.3086,1.32 0.26981,2.25 -0.70151,2.63 -0.62058,2.59 -0.56661,2.44 -0.5801,2.59 -0.60708,2.64 -0.70152,2.58 -0.62057,2.45 -0.56661,2.58 -0.5801,2.64 -0.60709,2.59 -0.70151,2.44 -0.62058,2.59 0.31029,2.15 1.32209,1.46 2.19899,0.78 2.3204,0.69 2.37437,0.78 2.3339,0.68 2.3204,0.78 2.37437,0.69 2.33389,0.63 2.19899,0.63 2.32041,0.69 2.37437,0.78 2.33389,0.68 2.19899,0.64 1.75379,-0.49 1.01181,-1.47 0.17538,-2.44 -0.17538,-2.44 -0.13491,-2.59 0.13491,-2.63 0.31028,-2.59 0.56662,-2.44 1.05227,-2.59 1.457,-2.64 1.8887,-2.44 2.06408,-1.95 2.3339,-1.47 2.36088,-0.97 2.33389,-0.64 2.3339,-0.14 2.37436,0.14 2.32041,0.64 2.19899,0.97 2.33389,1.81 2.19899,2.3 1.7538,2.58 1.18718,2.45 0.74199,2.58 0.5801,2.64 0.12142,2.59 -0.12142,2.44 -0.5801,2.59 -0.8769,2.63 -1.18718,2.59 -1.32209,2.44 -1.44351,2.59 -0.31029,2.15 0.8769,1.46 2.19899,0.79 2.33389,0.68 2.37437,0.78 2.32041,0.68 2.33389,0.79 2.37437,0.68 2.33389,0.63 2.1855,0.64 2.3339,0.68 2.37437,0.78 2.33389,0.69 2.1855,0.78 2.33389,0.68 h 2.06409 l 1.45699,-1.17 0.8769,-2.1 0.60708,-2.59 0.71501,-2.63 0.60708,-2.59 0.56661,-2.44 0.58011,-2.59 0.60708,-2.64 0.71501,-2.59 0.60708,-2.44 0.70152,-2.59 0.62057,-2.63 0.70152,-2.59 0.74199,-2.59 0.75548,-2.63 0.56661,-2.59 0.56661,-2.44 0.62057,-2.59 0.70152,-2.64 0.62057,-2.59 0.70152,-2.44 0.60708,-2.59 0.71501,-2.63 0.60709,-2.59 0.70151,-2.44 0.62058,-2.59 0.70151,-2.64 0.62058,-2.58 0.56661,-2.45 0.56661,-2.58 0.62057,-2.64 0.70152,-2.59 0.62057,-2.59 0.70152,-2.63 0.60708,-2.59 0.4452,-2.44 v -2.59 l -0.4452,-2.64 -1.18718,-2.58 -1.75379,-2.1 -2.3339,-1.66 -2.36088,-0.98 -2.33389,-0.64 -2.19899,-0.63 -2.3339,-0.83 -2.36087,-0.83 -2.3339,-0.64 -2.19899,-0.63 -2.33389,-0.68 -2.36088,-0.79 -2.33389,-0.68 -2.19899,-0.63 -2.3339,-0.64 -2.37437,-0.68 -2.3204,-0.78 -2.3339,-0.69 -2.37436,-0.78 -2.32041,-0.68 -2.19899,-0.64 -2.33389,-0.63 -2.37437,-0.68 -2.32041,-0.79 -2.19898,-0.68 -2.3339,-0.78 -2.37437,-0.68 -2.3204,-0.79 -2.19899,-0.68 -2.3339,-0.78 -2.37436,-0.68 -2.32041,-0.64 -2.19899,-0.63 -2.33389,-0.69 -2.37437,-0.78 -2.3204,-0.68 -2.19899,-0.64 -2.3339,-0.63 -2.37437,-0.69 -1.75379,-0.48 z"
fill="#2d6ad5"
id="path2"
style="stroke-width:1.1615" />
<path
d="m 282.02361,223.48 -1.45699,0.49 -2.19899,0.83 -2.1855,1.13 -2.19899,1.66 -2.06408,2.1 -1.59191,2.58 -1.18718,2.64 -0.74199,2.59 -0.44519,2.44 -0.12142,2.44 0.12142,2.44 0.44519,2.44 0.74199,2.45 0.75548,2.44 0.56661,2.44 -0.31028,2.29 -1.13323,1.47 -2.19898,0.63 h -2.37437 -2.3339 -2.19899 -2.19898 -2.1855 -2.19899 -2.19899 -2.19899 -2.19898 -2.19899 l -1.8887,0.34 -1.18719,1.13 -0.4317,2.1 v 2.63 2.59 2.44 2.44 2.45 2.44 2.44 l 0.4317,1.95 1.18719,0.98 1.8887,0.15 2.19899,-0.15 h 2.33389 l 2.37437,0.15 2.3204,0.48 2.19899,0.83 2.19899,0.98 2.19899,1.12 2.19899,1.47 2.19898,1.95 2.06409,2.3 1.8887,2.44 1.44351,2.44 1.32209,2.44 1.05227,2.59 0.8769,2.63 0.5801,2.59 0.2968,2.44 0.1349,2.45 -0.1349,2.44 -0.17538,2.44 -0.43171,2.44 -0.56661,2.44 -0.89038,2.44 -1.01181,2.44 -1.17369,2.45 -1.63238,2.44 -2.02361,2.58 -2.37437,2.3 -2.3204,1.95 -2.19899,1.32 -2.19899,1.12 -2.19899,0.83 -2.19898,0.64 -2.19899,0.34 -2.19899,0.15 -2.1855,-0.15 -2.19899,-0.34 -1.76728,0.15 -1.01181,1.31 -0.29679,2.3 v 2.59 2.44 2.44 2.44 2.44 2.44 2.45 l 0.56661,1.8 1.32209,0.98 2.06408,0.14 h 2.19899 2.3204 2.37437 2.3339 2.19899 2.19898 2.1855 2.19899 2.19899 2.19899 2.19898 2.19899 2.19899 2.32041 2.37436 2.3339 2.19899 2.19899 2.18549 2.19899 2.19899 2.19899 2.19899 2.19898 2.19899 2.19899 2.32041 2.37436 2.3339 2.19899 2.1855 2.19898 l 2.19899,-0.34 2.19899,-0.63 2.06408,-1.47 1.7538,-1.95 1.14671,-2.44 0.62057,-2.44 0.12142,-2.59 v -2.64 -2.59 -2.44 -2.44 -2.44 -2.44 -2.44 -2.44 -2.45 -2.44 -2.44 -2.44 -2.59 -2.63 -2.59 -2.44 -2.44 -2.45 -2.44 -2.44 -2.44 -2.44 -2.44 -2.44 -2.59 -2.64 -2.59 -2.44 -2.44 -2.44 -2.44 -2.44 -2.45 -2.44 -2.44 -2.44 -2.59 l -0.43171,-2.15 -1.18718,-1.27 -1.8887,-0.34 h -2.19899 -2.19899 -2.19899 -2.19898 -2.1855 -2.19899 -2.19899 -2.19899 -2.19899 -2.33389 l -2.1855,-0.63 -1.18718,-1.47 v -2.29 l 0.74199,-2.44 0.70152,-2.44 0.62057,-2.45 0.4317,-2.44 0.13491,-2.44 -0.13491,-2.44 -0.29679,-2.44 -0.75548,-2.44 -1.14672,-2.59 -1.75379,-2.64 -2.06408,-2.24 -2.19899,-1.66 -2.19899,-1.13 -2.19899,-0.83 -2.18549,-0.49 -1.63238,-0.14 z"
fill="#5187e1"
id="path3"
style="stroke-width:1.1615" />
<path
d="m 136,271.53 v 1.61 2.44 2.45 2.44 2.44 2.44 2.59 2.63 2.59 2.44 2.45 2.44 2.44 2.44 2.44 2.44 2.44 2.45 2.44 2.44 2.44 2.59 2.63 2.59 2.44 2.44 2.45 2.44 2.44 2.44 2.44 2.44 2.44 2.45 l 0.12142,2.44 0.62057,2.44 1.14671,2.44 1.92918,2.1 2.19898,1.46 2.3339,0.69 2.1855,0.14 h 2.19898 2.19899 2.19899 2.19899 2.19899 2.19899 2.18549 2.19899 2.19899 2.19899 2.19899 2.33389 2.36088 2.33389 2.19899 2.19899 2.19899 2.19899 2.1855 2.19898 2.19899 2.19899 2.19899 2.19899 2.19899 2.19898 2.32041 2.37437 2.33389 2.19899 2.1855 2.19899 2.19898 2.19899 2.19899 2.19899 2.19899 l 1.4435,-0.83 0.75549,-1.61 v -2.44 -2.44 -2.44 -2.59 -2.64 -2.58 -2.44 -2.45 -2.44 -2.44 -2.44 -2.44 -2.44 l 0.29679,-2.44 1.01181,-1.62 1.76728,-0.48 2.1855,0.63 2.19899,0.98 2.33389,0.97 2.37437,0.83 2.3204,0.49 h 2.19899 l 2.19899,-0.34 2.19899,-0.49 2.19899,-0.83 2.19899,-1.27 2.19898,-1.95 1.88871,-2.3 1.48398,-2.44 0.89038,-2.44 0.56661,-2.44 0.31029,-2.44 v -2.44 l -0.44519,-2.59 -0.74199,-2.64 -1.18719,-2.59 -1.457,-2.29 -1.8887,-2.1 -2.06408,-1.81 -2.19899,-1.27 -2.19898,-0.83 -2.1855,-0.34 -2.19899,-0.14 -2.19899,0.14 -2.19899,0.49 -2.19899,0.83 -2.19898,0.83 -2.19899,0.78 -2.1855,0.49 -1.76728,-0.63 -1.01181,-1.81 -0.29679,-2.59 v -2.44 -2.44 -2.44 -2.44 -2.45 -2.44 -2.44 -2.44 l -0.58011,-1.95 -1.32209,-1.13 -2.06408,-0.34 h -2.19899 -2.3204 -2.37437 -2.33389 -2.19899 -2.1855 -2.19899 l -1.32209,0.83 -0.56661,1.61 0.12142,2.44 v 2.45 l -0.12142,2.44 -0.31029,2.44 -0.5801,2.44 -0.74199,2.44 -1.0118,2.44 -1.32209,2.59 -1.7538,2.64 -2.06408,2.59 -2.19899,2.29 -2.19899,1.76 -2.19898,1.46 -2.1855,0.98 -2.19899,0.98 -2.19899,0.68 -2.19899,0.49 -2.19898,0.14 h -2.19899 l -2.19899,-0.14 -2.1855,-0.34 -2.19899,-0.64 -2.19898,-0.83 -2.3339,-1.12 -2.37437,-1.47 -2.3204,-1.95 -2.19899,-2.29 -2.06408,-2.45 -1.76729,-2.44 -1.3086,-2.44 -1.0118,-2.44 -0.75548,-2.44 -0.56661,-2.44 -0.31029,-2.44 -0.13491,-2.45 v -2.44 l 0.13491,-2.44 -0.4317,-1.81 -1.32209,-0.97 -2.19899,-0.15 h -2.3339 -2.1855 -2.19898 -2.19899 -2.19899 -2.19899 -1.61889 z"
fill="#71a0ed"
id="path4"
style="stroke-width:1.1615" />
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -1,8 +1,8 @@
document.addEventListener('DOMContentLoaded', () => {
const state = {
streak: parseInt(localStorage.getItem('chackly_streak') || '7'),
filesOrganized: parseInt(localStorage.getItem('chackly_files_organized') || '248'),
foldersManaged: parseInt(localStorage.getItem('chackly_folders') || '12')
streak: AppState.getStreak(),
filesOrganized: AppState.getFilesOrganized(),
foldersManaged: AppState.getFoldersManaged()
};
const suggestions = [

View File

@@ -1,36 +1,5 @@
document.addEventListener('DOMContentLoaded', () => {
// Data Management
const STORAGE_KEY = 'chackly_gamification';
const defaultData = {
streak: 12,
weeklyProgress: [true, true, true, true, false, false, false],
achievements: [
{ id: 'first_sort', name: '첫 정리', icon: '🏆', unlocked: true, tier: 'gold', requirement: '첫 정리 세션 완료' },
{ id: 'week_warrior', name: '주간 챌린저', icon: '🌟', unlocked: true, tier: 'gold', requirement: '7일 연속 완료' },
{ id: 'streak_7', name: '7일 스트릭', icon: '🔥', unlocked: true, tier: 'silver', requirement: '7일 스트릭 유지' },
{ id: 'diamond', name: '다이아몬드', icon: '💎', unlocked: true, tier: 'gold', requirement: '30일 스트릭 유지' },
{ id: 'organizer', name: '정리 달인', icon: '📦', unlocked: false, tier: 'silver', requirement: '100개 파일 정리' },
{ id: 'minimalist', name: '미니멀리스트', icon: '✨', unlocked: false, tier: 'bronze', requirement: '50개 파일 삭제' },
{ id: 'speed_demon', name: '스피드 데몬', icon: '⚡', unlocked: false, tier: 'gold', requirement: '하루에 50개 파일 정리' },
{ id: 'collector', name: '수집가', icon: '🗂️', unlocked: false, tier: 'silver', requirement: '5개 커스텀 폴더 생성' }
],
habitReminderEnabled: true,
lastUpdated: new Date().toISOString()
};
function loadData() {
const stored = localStorage.getItem(STORAGE_KEY);
if (stored) {
return { ...defaultData, ...JSON.parse(stored) };
}
return defaultData;
}
function saveData(data) {
data.lastUpdated = new Date().toISOString();
localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
}
let gamificationData = AppState.getGamificationData();
// UI Elements
const streakCount = document.getElementById('streakCount');
@@ -173,37 +142,37 @@ document.addEventListener('DOMContentLoaded', () => {
// Initialize page
function init() {
const data = loadData();
gamificationData = AppState.getGamificationData();
// Animate streak count
animateCount(streakCount, data.streak);
animateCount(streakCount, gamificationData.streak);
// Streak icon animation
if (data.streak > 0) {
if (gamificationData.streak > 0) {
streakIcon.classList.add('animate');
setTimeout(() => streakIcon.classList.remove('animate'), 1000);
}
// Update streak message
if (data.streak > 0) {
if (gamificationData.streak > 0) {
streakMessage.textContent = motivationalMessages[Math.floor(Math.random() * motivationalMessages.length)];
}
// Animate progress bar
const completedDays = data.weeklyProgress.filter(Boolean).length;
const completedDays = gamificationData.weeklyProgress.filter(Boolean).length;
setTimeout(() => {
progressFill.style.width = (completedDays / 7 * 100) + '%';
}, 300);
daysCompleted.textContent = completedDays;
// Render week grid
renderWeekGrid(data.weeklyProgress);
renderWeekGrid(gamificationData.weeklyProgress);
// Render achievements
renderAchievements(data.achievements);
renderAchievements(gamificationData.achievements);
// Set habit toggle state
habitToggle.checked = data.habitReminderEnabled;
habitToggle.checked = gamificationData.habitReminderEnabled;
// Random daily tip
const randomTip = dailyTips[Math.floor(Math.random() * dailyTips.length)];
@@ -212,8 +181,8 @@ document.addEventListener('DOMContentLoaded', () => {
// Habit toggle handler
habitToggle.addEventListener('change', (e) => {
data.habitReminderEnabled = e.target.checked;
saveData(data);
gamificationData.habitReminderEnabled = e.target.checked;
AppState.setGamificationData(gamificationData);
showToast(e.target.checked ? '🔔' : '🔕', e.target.checked ? 'Reminders enabled!' : 'Reminders disabled');
});
@@ -223,14 +192,14 @@ document.addEventListener('DOMContentLoaded', () => {
if (achievement && !achievement.classList.contains('unlocked')) {
// Simulate unlock for demo
const achId = achievement.dataset.id;
const achData = data.achievements.find(a => a.id === achId);
const achData = gamificationData.achievements.find(a => a.id === achId);
if (achData) {
achData.unlocked = true;
saveData(data);
AppState.setGamificationData(gamificationData);
animateBadgeUnlock(achId);
triggerConfetti();
showToast(achData.icon, `${achData.name} unlocked!`);
renderAchievements(data.achievements);
renderAchievements(gamificationData.achievements);
}
}
});

View File

@@ -1,7 +1,7 @@
document.addEventListener('DOMContentLoaded', () => {
const state = {
theme: localStorage.getItem('chackly_theme') || 'light',
settings: JSON.parse(localStorage.getItem('chackly_settings') || '{"notifications":true,"habits":false,"autoOrganize":false,"confirmDelete":true}')
theme: AppState.getTheme(),
settings: AppState.getSettings()
};
function initToggles() {
@@ -24,9 +24,8 @@ document.addEventListener('DOMContentLoaded', () => {
});
option.classList.remove('border-transparent');
option.classList.add('border-primary');
AppState.setTheme(option.dataset.theme);
state.theme = option.dataset.theme;
localStorage.setItem('chackly_theme', state.theme);
document.documentElement.setAttribute('data-theme', state.theme);
});
});
@@ -44,7 +43,7 @@ document.addEventListener('DOMContentLoaded', () => {
autoOrganize: document.getElementById('toggle-autoOrganize')?.classList.contains('active'),
confirmDelete: document.getElementById('toggle-confirmDelete')?.classList.contains('active')
};
localStorage.setItem('chackly_settings', JSON.stringify(settings));
AppState.setSettings(settings);
}
document.getElementById('export-data')?.addEventListener('click', () => {

106
src/scripts/shared/state.js Normal file
View File

@@ -0,0 +1,106 @@
/**
* AppState - Shared state management module
* Handles all localStorage interactions for the Chakmate app
*/
const AppState = {
// ============ Theme ============
getTheme() {
return localStorage.getItem('chackly_theme') || 'light';
},
setTheme(theme) {
localStorage.setItem('chackly_theme', theme);
document.documentElement.setAttribute('data-theme', theme);
},
// ============ Settings ============
getSettings() {
const defaults = {
notifications: true,
habits: false,
autoOrganize: false,
confirmDelete: true
};
try {
return { ...defaults, ...JSON.parse(localStorage.getItem('chackly_settings') || '{}') };
} catch {
return defaults;
}
},
setSettings(settings) {
localStorage.setItem('chackly_settings', JSON.stringify(settings));
},
// ============ Gamification ============
getGamificationData() {
const defaultData = {
streak: 12,
weeklyProgress: [true, true, true, true, false, false, false],
achievements: [
{ id: 'first_sort', name: '첫 정리', icon: '🏆', unlocked: true, tier: 'gold', requirement: '첫 정리 세션 완료' },
{ id: 'week_warrior', name: '주간 챌린저', icon: '🌟', unlocked: true, tier: 'gold', requirement: '7일 연속 완료' },
{ id: 'streak_7', name: '7일 스트릭', icon: '🔥', unlocked: true, tier: 'silver', requirement: '7일 스트릭 유지' },
{ id: 'diamond', name: '다이아몬드', icon: '💎', unlocked: true, tier: 'gold', requirement: '30일 스트릭 유지' },
{ id: 'organizer', name: '정리 달인', icon: '📦', unlocked: false, tier: 'silver', requirement: '100개 파일 정리' },
{ id: 'minimalist', name: '미니멀리스트', icon: '✨', unlocked: false, tier: 'bronze', requirement: '50개 파일 삭제' },
{ id: 'speed_demon', name: '스피드 데몬', icon: '⚡', unlocked: false, tier: 'gold', requirement: '하루에 50개 파일 정리' },
{ id: 'collector', name: '수집가', icon: '🗂️', unlocked: false, tier: 'silver', requirement: '5개 커스텀 폴더 생성' }
],
habitReminderEnabled: true,
lastUpdated: new Date().toISOString()
};
try {
const stored = localStorage.getItem('chackly_gamification');
if (stored) {
return { ...defaultData, ...JSON.parse(stored) };
}
} catch {
// ignore
}
return defaultData;
},
setGamificationData(data) {
data.lastUpdated = new Date().toISOString();
localStorage.setItem('chackly_gamification', JSON.stringify(data));
},
// ============ Dashboard Stats ============
getStreak() {
return parseInt(localStorage.getItem('chackly_streak') || '7');
},
setStreak(count) {
localStorage.setItem('chackly_streak', count.toString());
},
getFilesOrganized() {
return parseInt(localStorage.getItem('chackly_files_organized') || '248');
},
setFilesOrganized(count) {
localStorage.setItem('chackly_files_organized', count.toString());
},
getFoldersManaged() {
return parseInt(localStorage.getItem('chackly_folders') || '12');
},
setFoldersManaged(count) {
localStorage.setItem('chackly_folders', count.toString());
},
// ============ Initialization ============
init() {
// Apply saved theme on page load
const theme = this.getTheme();
document.documentElement.setAttribute('data-theme', theme);
}
};
// Auto-initialize when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
AppState.init();
});

View File

@@ -1,3 +1,12 @@
@import '@fontsource/noto-sans-kr/300.css';
@import '@fontsource/noto-sans-kr/400.css';
@import '@fontsource/noto-sans-kr/500.css';
@import '@fontsource/noto-sans-kr/700.css';
@import '@fontsource/outfit/400.css';
@import '@fontsource/outfit/500.css';
@import '@fontsource/outfit/600.css';
@import '@fontsource/outfit/700.css';
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -8,7 +8,6 @@ export default defineConfig({
emptyOutDir: true,
rollupOptions: {
input: {
main: resolve(__dirname, 'src/index.html'),
onboarding: resolve(__dirname, 'src/pages/scene_onboarding.html'),
dashboard: resolve(__dirname, 'src/pages/scene_dashboard.html'),
swipe: resolve(__dirname, 'src/pages/scene_swipe.html'),
@@ -16,9 +15,16 @@ export default defineConfig({
'ai-classification': resolve(__dirname, 'src/pages/scene_ai_classification.html'),
gamification: resolve(__dirname, 'src/pages/scene_gamification.html'),
visualization: resolve(__dirname, 'src/pages/scene_visualization.html'),
},
output: {
assetFileNames: (assetInfo) => {
if (assetInfo.name === 'logo.svg') return 'assets/[name][extname]';
return 'assets/[name]-[hash][extname]';
}
}
}
},
publicDir: 'public',
server: {
port: 5173,
strictPort: true