diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 662ddaf..6979e26 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -98,7 +98,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -748,7 +747,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.27.1.tgz", "integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1632,7 +1630,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-module-imports": "^7.27.1", @@ -5046,7 +5043,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", "license": "MIT", - "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -5171,7 +5167,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.4.0", "@typescript-eslint/scope-manager": "5.62.0", @@ -5225,7 +5220,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -5595,7 +5589,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5694,7 +5687,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -6660,7 +6652,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001735", "electron-to-chromium": "^1.5.204", @@ -6865,7 +6856,6 @@ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.0.tgz", "integrity": "sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==", "license": "MIT", - "peer": true, "dependencies": { "@kurkle/color": "^0.3.0" }, @@ -7711,8 +7701,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/d3": { "version": "7.9.0", @@ -8031,7 +8020,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -8979,7 +8967,6 @@ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -11862,7 +11849,6 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "^27.5.1", "import-local": "^3.0.2", @@ -15209,8 +15195,7 @@ "version": "0.36.1", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.36.1.tgz", "integrity": "sha512-/CaclMHKQ3A6rnzBzOADfwdSJ25BFoFT0Emxsc4zYVyav5SkK9iA6lEtIeuN/oRYbwPgviJT+t3l+sjFa28jYg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/ms": { "version": "2.1.3", @@ -15971,7 +15956,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -17159,7 +17143,6 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "license": "MIT", - "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -17516,7 +17499,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -17677,7 +17659,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -17729,7 +17710,6 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -18238,7 +18218,6 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "license": "MIT", - "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -18490,7 +18469,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -19744,7 +19722,6 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "license": "MIT", - "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -20125,7 +20102,6 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "license": "(MIT OR CC0-1.0)", - "peer": true, "engines": { "node": ">=10" }, @@ -20234,7 +20210,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -20561,7 +20536,6 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.101.3.tgz", "integrity": "sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==", "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -20633,7 +20607,6 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", "license": "MIT", - "peer": true, "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -21046,7 +21019,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", diff --git a/frontend/src/App.css b/frontend/src/App.css index 38c69fc..bcbe61b 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1,49 +1,151 @@ :root { - /* Light theme variables */ - --bg-primary: #f9fafb; - --bg-secondary: #ffffff; - --text-primary: #111827; - --text-secondary: #4b5563; - --accent-primary: #3b82f6; - --accent-secondary: #60a5fa; - --border-color: #e5e7eb; - --shadow-color: rgba(0, 0, 0, 0.1); - + /* Light theme color tokens */ + --surface-primary: 249 250 251; /* gray-50 */ + --surface-secondary: 255 255 255; /* white */ + --surface-tertiary: 243 244 246; /* gray-100 */ + --surface-elevated: 255 255 255; /* white */ + + --content-primary: 17 24 39; /* gray-900 */ + --content-secondary: 75 85 99; /* gray-600 */ + --content-tertiary: 156 163 175; /* gray-400 */ + --content-inverse: 255 255 255; /* white */ + + --border-primary: 229 231 235; /* gray-200 */ + --border-secondary: 209 213 219; /* gray-300 */ + --border-accent: 59 130 246; /* blue-500 */ + + /* Brand colors */ + --brand-primary: 59 130 246; /* blue-500 */ + --brand-secondary: 147 51 234; /* purple-600 */ + --brand-accent: 20 184 166; /* teal-500 */ + + /* Algorithm colors */ + --algo-default: 100 116 139; /* slate-500 */ + --algo-current: 239 68 68; /* red-500 */ + --algo-comparing: 245 158 11; /* amber-500 */ + --algo-completed: 34 197 94; /* green-500 */ + --algo-visited: 59 130 246; /* blue-500 */ + + /* Status colors */ + --status-success: 34 197 94; /* green-500 */ + --status-warning: 245 158 11; /* amber-500 */ + --status-error: 239 68 68; /* red-500 */ + --status-info: 59 130 246; /* blue-500 */ + + /* Gradients */ + --gradient-primary: linear-gradient(135deg, rgb(59 130 246) 0%, rgb(147 51 234) 100%); + --gradient-secondary: linear-gradient(135deg, rgb(20 184 166) 0%, rgb(59 130 246) 100%); + --gradient-accent: linear-gradient(135deg, rgb(244 63 94) 0%, rgb(251 146 60) 100%); + --gradient-subtle: linear-gradient(135deg, rgb(243 244 246) 0%, rgb(255 255 255) 100%); + + /* Shadows */ + --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); + /* Animation durations */ - --transition-duration: 300ms; + --transition-fast: 150ms; + --transition-base: 300ms; + --transition-slow: 500ms; --transition-timing: cubic-bezier(0.4, 0, 0.2, 1); } -:root[class~="dark"] { - /* Dark theme variables */ - --bg-primary: #111827; - --bg-secondary: #1f2937; - --text-primary: #f9fafb; - --text-secondary: #d1d5db; - --accent-primary: #60a5fa; - --accent-secondary: #93c5fd; - --border-color: #374151; - --shadow-color: rgba(0, 0, 0, 0.25); +:root.dark { + /* Dark theme color tokens */ + --surface-primary: 17 24 39; /* gray-900 */ + --surface-secondary: 31 41 55; /* gray-800 */ + --surface-tertiary: 55 65 81; /* gray-700 */ + --surface-elevated: 31 41 55; /* gray-800 */ + + --content-primary: 249 250 251; /* gray-50 */ + --content-secondary: 209 213 219; /* gray-300 */ + --content-tertiary: 156 163 175; /* gray-400 */ + --content-inverse: 17 24 39; /* gray-900 */ + + --border-primary: 55 65 81; /* gray-700 */ + --border-secondary: 75 85 99; /* gray-600 */ + --border-accent: 96 165 250; /* blue-400 */ + + /* Brand colors (adjusted for dark mode) */ + --brand-primary: 96 165 250; /* blue-400 */ + --brand-secondary: 168 85 247; /* purple-400 */ + --brand-accent: 45 212 191; /* teal-400 */ + + /* Algorithm colors (adjusted for dark mode) */ + --algo-default: 148 163 184; /* slate-400 */ + --algo-current: 248 113 113; /* red-400 */ + --algo-comparing: 251 191 36; /* amber-400 */ + --algo-completed: 74 222 128; /* green-400 */ + --algo-visited: 96 165 250; /* blue-400 */ + + /* Status colors (adjusted for dark mode) */ + --status-success: 74 222 128; /* green-400 */ + --status-warning: 251 191 36; /* amber-400 */ + --status-error: 248 113 113; /* red-400 */ + --status-info: 96 165 250; /* blue-400 */ + + /* Gradients (adjusted for dark mode) */ + --gradient-primary: linear-gradient(135deg, rgb(96 165 250) 0%, rgb(168 85 247) 100%); + --gradient-secondary: linear-gradient(135deg, rgb(45 212 191) 0%, rgb(96 165 250) 100%); + --gradient-accent: linear-gradient(135deg, rgb(251 113 133) 0%, rgb(251 191 36) 100%); + --gradient-subtle: linear-gradient(135deg, rgb(55 65 81) 0%, rgb(31 41 55) 100%); + + /* Shadows (enhanced for dark mode) */ + --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.3); + --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.4), 0 2px 4px -2px rgb(0 0 0 / 0.3); + --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.4), 0 4px 6px -4px rgb(0 0 0 / 0.3); + --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.4), 0 8px 10px -6px rgb(0 0 0 / 0.3); } -/* Apply transitions to theme changes */ +/* Apply smooth transitions to theme changes */ *, *::before, *::after { - transition: background-color var(--transition-duration) var(--transition-timing), - border-color var(--transition-duration) var(--transition-timing), - color var(--transition-duration) var(--transition-timing), - box-shadow var(--transition-duration) var(--transition-timing); + transition: + background-color var(--transition-base) var(--transition-timing), + border-color var(--transition-base) var(--transition-timing), + color var(--transition-base) var(--transition-timing), + box-shadow var(--transition-base) var(--transition-timing), + opacity var(--transition-base) var(--transition-timing), + transform var(--transition-base) var(--transition-timing); } .App { min-height: 100vh; - background-color: var(--bg-primary); - color: var(--text-primary); + background-color: rgb(var(--surface-primary)); + color: rgb(var(--content-primary)); } +/* Theme-aware utility classes */ +.bg-surface-primary { background-color: rgb(var(--surface-primary)); } +.bg-surface-secondary { background-color: rgb(var(--surface-secondary)); } +.bg-surface-tertiary { background-color: rgb(var(--surface-tertiary)); } +.bg-surface-elevated { background-color: rgb(var(--surface-elevated)); } + +.text-content-primary { color: rgb(var(--content-primary)); } +.text-content-secondary { color: rgb(var(--content-secondary)); } +.text-content-tertiary { color: rgb(var(--content-tertiary)); } +.text-content-inverse { color: rgb(var(--content-inverse)); } + +.border-primary { border-color: rgb(var(--border-primary)); } +.border-secondary { border-color: rgb(var(--border-secondary)); } +.border-accent { border-color: rgb(var(--border-accent)); } + +.bg-gradient-primary { background: var(--gradient-primary); } +.bg-gradient-secondary { background: var(--gradient-secondary); } +.bg-gradient-accent { background: var(--gradient-accent); } +.bg-gradient-subtle { background: var(--gradient-subtle); } + +/* Algorithm visualization classes */ +.algo-default { background-color: rgb(var(--algo-default)); } +.algo-current { background-color: rgb(var(--algo-current)); } +.algo-comparing { background-color: rgb(var(--algo-comparing)); } +.algo-completed { background-color: rgb(var(--algo-completed)); } +.algo-visited { background-color: rgb(var(--algo-visited)); } + /* Loading spinner */ .spinner { - border: 4px solid #f3f3f3; - border-top: 4px solid #3b82f6; + border: 4px solid rgb(var(--border-primary)); + border-top: 4px solid rgb(var(--brand-primary)); border-radius: 50%; width: 40px; height: 40px; @@ -55,58 +157,137 @@ 100% { transform: rotate(360deg); } } -/* Button animations */ +/* Enhanced button styles */ .btn-primary { - @apply bg-primary-600 text-white px-4 py-2 rounded-lg hover:bg-primary-700 transition-colors duration-200; + background-color: rgb(37 99 235); + color: white; + padding: 0.5rem 1rem; + border-radius: 0.5rem; + transition: all 200ms ease; + border: none; + cursor: pointer; + font-weight: 500; +} + +.btn-primary:hover { + background-color: rgb(29 78 216); +} + +.btn-primary:focus { + outline: none; + box-shadow: 0 0 0 2px rgb(59 130 246), 0 0 0 4px rgba(59, 130, 246, 0.3); } .btn-secondary { - @apply bg-gray-200 text-gray-800 px-4 py-2 rounded-lg hover:bg-gray-300 transition-colors duration-200; + background-color: rgb(var(--surface-secondary)); + color: rgb(var(--content-primary)); + padding: 0.5rem 1rem; + border-radius: 0.5rem; + border: 1px solid rgb(var(--border-primary)); + transition: all 200ms ease; + cursor: pointer; + font-weight: 500; +} + +.btn-secondary:hover { + background-color: rgb(var(--surface-tertiary)); +} + +.btn-secondary:focus { + outline: none; + box-shadow: 0 0 0 2px rgb(59 130 246), 0 0 0 4px rgba(59, 130, 246, 0.3); +} + +.btn-ghost { + color: rgb(var(--content-primary)); + padding: 0.5rem 1rem; + border-radius: 0.5rem; + border: none; + background: transparent; + transition: all 200ms ease; + cursor: pointer; + font-weight: 500; +} + +.btn-ghost:hover { + background-color: rgb(var(--surface-tertiary)); +} + +.btn-ghost:focus { + outline: none; + box-shadow: 0 0 0 2px rgb(59 130 246), 0 0 0 4px rgba(59, 130, 246, 0.3); +} + +/* Card styles */ +.card { + background-color: rgb(var(--surface-secondary)); + border: 1px solid rgb(var(--border-primary)); + border-radius: 0.5rem; + box-shadow: var(--shadow-md); +} + +.card-elevated { + background-color: rgb(var(--surface-elevated)); + border: 1px solid rgb(var(--border-primary)); + border-radius: 0.5rem; + box-shadow: var(--shadow-lg); } -/* Card hover effects */ .card-hover { - transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out; + transition: transform var(--transition-base) var(--transition-timing), + box-shadow var(--transition-base) var(--transition-timing); } .card-hover:hover { transform: translateY(-2px); - box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1); + box-shadow: var(--shadow-xl); +} + +/* Glass morphism effect */ +.glass { + background: rgba(255, 255, 255, 0.1); + backdrop-filter: blur(16px); + border: 1px solid rgba(255, 255, 255, 0.2); +} + +.dark .glass { + background: rgba(31, 41, 55, 0.3); + border: 1px solid rgba(75, 85, 99, 0.3); } /* Algorithm visualization specific styles */ .algorithm-bar { - transition: all 0.3s ease-in-out; + transition: all var(--transition-base) var(--transition-timing); } .algorithm-bar.comparing { - background-color: #ef4444; + background-color: rgb(var(--algo-comparing)); transform: scale(1.05); } .algorithm-bar.highlighted { - background-color: #10b981; + background-color: rgb(var(--algo-current)); transform: scale(1.05); } .algorithm-bar.sorted { - background-color: #8b5cf6; + background-color: rgb(var(--algo-completed)); } /* Graph node styles */ .graph-node { - transition: all 0.3s ease-in-out; + transition: all var(--transition-base) var(--transition-timing); } .graph-node.visited { - fill: #10b981; - stroke: #059669; + fill: rgb(var(--algo-visited)); + stroke: rgb(var(--algo-visited)); stroke-width: 2; } .graph-node.current { - fill: #ef4444; - stroke: #dc2626; + fill: rgb(var(--algo-current)); + stroke: rgb(var(--algo-current)); stroke-width: 3; animation: pulse 1s infinite; } @@ -116,18 +297,11 @@ 50% { transform: scale(1.1); } } -/* Code editor styles */ -.monaco-editor-container { - border: 1px solid #e5e7eb; - border-radius: 8px; - overflow: hidden; -} - -/* Responsive design */ +/* Responsive design improvements */ @media (max-width: 768px) { .sidebar { transform: translateX(-100%); - transition: transform 0.3s ease-in-out; + transition: transform var(--transition-base) var(--transition-timing); } .sidebar.open { diff --git a/frontend/src/App.js b/frontend/src/App.js index 84633f4..c9c0fcd 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,8 +1,8 @@ -import React, { useState, useEffect } from 'react'; +import React from 'react'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import { Toaster } from 'react-hot-toast'; +import { ThemeProvider, useTheme } from './contexts/ThemeContext'; import Layout from './components/Layout/Layout'; -import { getUserPreferences, setUserPreferences } from './services/userPreferences'; import SortingVisualizer from './pages/SortingVisualizer'; import GraphVisualizer from './pages/GraphVisualizer'; import StringVisualizer from './pages/StringVisualizer'; @@ -14,112 +14,100 @@ import ContributorsPage from './pages/ContributorsPage'; import NotFoundPage from './pages/NotFoundPage'; import './App.css'; -function App() { - // Theme state with persistence - const [theme, setTheme] = useState(() => { - // Check system preference first - const systemPreference = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; - try { - const { theme: savedTheme } = getUserPreferences(); - return savedTheme || systemPreference; - } catch (error) { - console.error('Error loading theme preference:', error); - return systemPreference; - } - }); - - // Update theme and save preference - const handleThemeChange = (newTheme) => { - setTheme(newTheme); - - // Save to localStorage - const preferences = getUserPreferences(); - setUserPreferences({ ...preferences, theme: newTheme }); - - // Update document class for global styling - if (newTheme === 'dark') { - document.documentElement.classList.add('dark'); - } else { - document.documentElement.classList.remove('dark'); - } - }; - - // Listen for system theme changes - useEffect(() => { - const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); - const handleChange = (e) => { - const systemTheme = e.matches ? 'dark' : 'light'; - handleThemeChange(systemTheme); - }; - - mediaQuery.addEventListener('change', handleChange); - return () => mediaQuery.removeEventListener('change', handleChange); - }, []); - - // Apply theme on mount and changes - useEffect(() => { - handleThemeChange(theme); - }, [theme]); +const AppContent = () => { + const { isDark } = useTheme(); return (
- Want to join our mission? Read our{" "} +const CTASection = () => { + const { classes } = useTheme(); + + return ( +
+ Want to join our mission? Read our{" "} + + contribution guidelines + {" "} + and pick an{" "} + + open issue + {" "} + to get started. +
- contribution guidelines - {" "} - and pick an{" "} - - open issue - {" "} - to get started. - - - Contribute Now - -- {desc} -
-+ {desc} +
+- {contributor.contributions} contributions -
- { + const { isDark, classes } = useTheme(); + + return ( ++ {contributor.contributions} contributions +
+ ++
Loading contributors...
); @@ -16,7 +15,7 @@ const ContributorsGrid = ({ contributors, loading, error, darkMode }) => { return ({ + const { isDark, classes } = useTheme(); + + return ( +
+ This project is made possible thanks to the amazing contributions from our + community members. Explore their work and join us in making this even + better. +
+