refactor: restructure project with shared state and public assets
This commit is contained in:
20
package-lock.json
generated
20
package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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
56
src/public/logo.svg
Normal 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 |
@@ -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 = [
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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
106
src/scripts/shared/state.js
Normal 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();
|
||||
});
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user