diff --git a/TaskTracker.Web/index.html b/TaskTracker.Web/index.html
index 22fe403..f27f58a 100644
--- a/TaskTracker.Web/index.html
+++ b/TaskTracker.Web/index.html
@@ -7,7 +7,7 @@
-
tasktracker-web
+ TaskTracker
diff --git a/TaskTracker.Web/package-lock.json b/TaskTracker.Web/package-lock.json
index 6aec30f..9b4d73b 100644
--- a/TaskTracker.Web/package-lock.json
+++ b/TaskTracker.Web/package-lock.json
@@ -13,6 +13,7 @@
"@dnd-kit/utilities": "^3.2.2",
"@tanstack/react-query": "^5.90.21",
"axios": "^1.13.5",
+ "framer-motion": "^12.34.3",
"lucide-react": "^0.575.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
@@ -3195,6 +3196,33 @@
"node": ">= 6"
}
},
+ "node_modules/framer-motion": {
+ "version": "12.34.3",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.34.3.tgz",
+ "integrity": "sha512-v81ecyZKYO/DfpTwHivqkxSUBzvceOpoI+wLfgCgoUIKxlFKEXdg0oR9imxwXumT4SFy8vRk9xzJ5l3/Du/55Q==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-dom": "^12.34.3",
+ "motion-utils": "^12.29.2",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "@emotion/is-prop-valid": "*",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/is-prop-valid": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -3469,7 +3497,6 @@
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"jiti": "lib/jiti-cli.mjs"
}
@@ -3571,7 +3598,6 @@
"integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==",
"dev": true,
"license": "MPL-2.0",
- "peer": true,
"dependencies": {
"detect-libc": "^2.0.3"
},
@@ -3922,6 +3948,21 @@
"node": "*"
}
},
+ "node_modules/motion-dom": {
+ "version": "12.34.3",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.34.3.tgz",
+ "integrity": "sha512-sYgFe+pR9aIM7o4fhs2aXtOI+oqlUd33N9Yoxcgo1Fv7M20sRkHtCmzE/VRNIcq7uNJ+qio+Xubt1FXH3pQ+eQ==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-utils": "^12.29.2"
+ }
+ },
+ "node_modules/motion-utils": {
+ "version": "12.29.2",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.29.2.tgz",
+ "integrity": "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A==",
+ "license": "MIT"
+ },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
diff --git a/TaskTracker.Web/package.json b/TaskTracker.Web/package.json
index 3c4bab5..d47d204 100644
--- a/TaskTracker.Web/package.json
+++ b/TaskTracker.Web/package.json
@@ -15,6 +15,7 @@
"@dnd-kit/utilities": "^3.2.2",
"@tanstack/react-query": "^5.90.21",
"axios": "^1.13.5",
+ "framer-motion": "^12.34.3",
"lucide-react": "^0.575.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
diff --git a/TaskTracker.Web/src/index.css b/TaskTracker.Web/src/index.css
index 9540225..a9661ed 100644
--- a/TaskTracker.Web/src/index.css
+++ b/TaskTracker.Web/src/index.css
@@ -2,22 +2,81 @@
@theme {
--font-sans: 'Inter', system-ui, sans-serif;
+ --color-page: #0a0a0f;
+ --color-surface: #12131a;
+ --color-elevated: #1a1b26;
+ --color-border: rgba(255, 255, 255, 0.06);
+ --color-border-hover: rgba(255, 255, 255, 0.12);
+ --color-text-primary: #e2e8f0;
+ --color-text-secondary: #64748b;
+ --color-text-tertiary: #334155;
+ --color-accent: #8b5cf6;
+ --color-accent-end: #6366f1;
+ --color-status-active: #3b82f6;
+ --color-status-paused: #eab308;
+ --color-status-completed: #22c55e;
+ --color-status-pending: #64748b;
}
+/* Noise grain texture */
+body::before {
+ content: '';
+ position: fixed;
+ inset: 0;
+ z-index: 9999;
+ pointer-events: none;
+ opacity: 0.03;
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
+ background-repeat: repeat;
+ background-size: 256px 256px;
+}
+
+/* Active task pulse */
@keyframes pulse-glow {
0%, 100% {
- box-shadow: 0 0 8px rgba(6, 182, 212, 0.3);
+ box-shadow: 0 0 6px rgba(59, 130, 246, 0.3);
}
50% {
- box-shadow: 0 0 20px rgba(6, 182, 212, 0.5);
+ box-shadow: 0 0 16px rgba(59, 130, 246, 0.5);
}
}
.animate-pulse-glow {
- animation: pulse-glow 2s ease-in-out infinite;
+ animation: pulse-glow 2.5s ease-in-out infinite;
}
-/* Custom scrollbar for dark theme */
+/* Live dot pulse */
+@keyframes live-dot {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0.4; }
+}
+
+.animate-live-dot {
+ animation: live-dot 1.5s ease-in-out infinite;
+}
+
+/* Card hover glow border */
+.card-glow {
+ position: relative;
+}
+
+.card-glow::before {
+ content: '';
+ position: absolute;
+ inset: -1px;
+ border-radius: inherit;
+ background: linear-gradient(135deg, rgba(139, 92, 246, 0.2), rgba(99, 102, 241, 0.1), transparent);
+ opacity: 0;
+ transition: opacity 0.2s ease;
+ z-index: -1;
+ pointer-events: none;
+}
+
+.card-glow:hover::before {
+ opacity: 1;
+}
+
+/* Custom scrollbar */
::-webkit-scrollbar {
width: 6px;
}
@@ -27,10 +86,15 @@
}
::-webkit-scrollbar-thumb {
- background: #2a2d37;
+ background: #1a1b26;
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
- background: #3a3d47;
+ background: #2a2d37;
+}
+
+/* Selection color */
+::selection {
+ background: rgba(139, 92, 246, 0.3);
}
diff --git a/TaskTracker.Web/src/lib/constants.ts b/TaskTracker.Web/src/lib/constants.ts
index 291eb95..f2f1e57 100644
--- a/TaskTracker.Web/src/lib/constants.ts
+++ b/TaskTracker.Web/src/lib/constants.ts
@@ -1,8 +1,8 @@
export const COLUMN_CONFIG = [
- { status: 'Pending' as const, label: 'Pending', color: '#94a3b8' },
- { status: 'Active' as const, label: 'Active', color: '#06b6d4' },
- { status: 'Paused' as const, label: 'Paused', color: '#f59e0b' },
- { status: 'Completed' as const, label: 'Completed', color: '#10b981' },
+ { status: 'Pending' as const, label: 'Pending', color: '#64748b' },
+ { status: 'Active' as const, label: 'Active', color: '#3b82f6' },
+ { status: 'Paused' as const, label: 'Paused', color: '#eab308' },
+ { status: 'Completed' as const, label: 'Completed', color: '#22c55e' },
] as const
export const CATEGORY_COLORS: Record = {
@@ -12,5 +12,10 @@ export const CATEGORY_COLORS: Record = {
DevOps: '#f97316',
Documentation: '#14b8a6',
Design: '#ec4899',
- Unknown: '#64748b',
+ Testing: '#3b82f6',
+ General: '#64748b',
+ Email: '#f59e0b',
+ Engineering: '#6366f1',
+ LaserCutting: '#ef4444',
+ Unknown: '#475569',
}