From f83e0875417cec43336c3e05ee03e454c3ab5d1b Mon Sep 17 00:00:00 2001 From: Deco Vander Date: Fri, 4 Jul 2025 11:30:34 -0400 Subject: [PATCH] Optimize CSS architecture with SCSS modular system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Major CSS/SCSS Improvements - ✅ Set up modular SCSS architecture with variables, mixins, and components - ✅ Created organized directory structure: src/scss/ with variables, mixins, pages/ - ✅ Removed ~300+ lines of inline CSS from admin.html - ✅ Added comprehensive design system with consistent spacing, colors, typography - ✅ Created reusable mixins for buttons, cards, tables, forms, and layouts - ✅ Implemented responsive breakpoint mixins for mobile/tablet/desktop - ✅ Added utility classes for common layouts and spacing ## Build System - ✅ Added sass and concurrently as dev dependencies - ✅ Created npm scripts: build-css, watch-css, dev-with-css - ✅ Automated SCSS compilation to compressed CSS - ✅ Set up development workflow with CSS watching ## Admin Panel Enhancements - ✅ Added complete tab navigation system (Location Reports + Profanity Filter) - ✅ Integrated profanity management UI with forms and tables - ✅ Consistent styling across all components using SCSS mixins - ✅ Improved responsive design for mobile devices ## Benefits - 🎯 Maintainable: All styles centralized in modular SCSS files - 📱 Responsive: Better mobile experience with consistent breakpoints - 🎨 Consistent: Design system ensures visual consistency - ⚡ Efficient: Compressed CSS output, no inline styles - 🔧 Developer-friendly: Easy to extend and modify styles The application now has professional-grade CSS architecture that's easy to maintain and extend. --- package-lock.json | 700 ++++++++++++++++++++++++++++++++++++- package.json | 10 +- public/admin.html | 400 ++++----------------- public/style.css | 596 +------------------------------ public/style.css.map | 1 + src/scss/_mixins.scss | 137 ++++++++ src/scss/_variables.scss | 55 +++ src/scss/main.scss | 142 ++++++++ src/scss/pages/_admin.scss | 304 ++++++++++++++++ 9 files changed, 1414 insertions(+), 931 deletions(-) create mode 100644 public/style.css.map create mode 100644 src/scss/_mixins.scss create mode 100644 src/scss/_variables.scss create mode 100644 src/scss/main.scss create mode 100644 src/scss/pages/_admin.scss diff --git a/package-lock.json b/package-lock.json index d8eb820..146b74b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,9 @@ "sqlite3": "^5.1.6" }, "devDependencies": { - "nodemon": "^3.0.1" + "concurrently": "^9.2.0", + "nodemon": "^3.0.1", + "sass": "^1.89.2" } }, "node_modules/@gar/promisify": { @@ -52,6 +54,330 @@ "node": ">=10" } }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -151,12 +477,28 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "devOptional": true, "license": "MIT", - "optional": true, "engines": { "node": ">=8" } }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -399,6 +741,46 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -443,6 +825,41 @@ "node": ">=6" } }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", @@ -460,6 +877,58 @@ "devOptional": true, "license": "MIT" }, + "node_modules/concurrently": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.0.tgz", + "integrity": "sha512-IsB/fiXTupmagMW4MNp2lx2cdSN2FfZq78vF90LBB+zZHArbIQZjQtzXCiXnvTxCZSvXanTqFLWBjw2UkLx1SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -620,8 +1089,8 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT", - "optional": true + "devOptional": true, + "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", @@ -711,6 +1180,16 @@ "node": ">= 0.4" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -906,6 +1385,16 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -1195,6 +1684,13 @@ "dev": true, "license": "ISC" }, + "node_modules/immutable": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", + "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", + "dev": true, + "license": "MIT" + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -1296,8 +1792,8 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "devOptional": true, "license": "MIT", - "optional": true, "engines": { "node": ">=8" } @@ -1346,6 +1842,13 @@ "license": "MIT", "optional": true }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -1423,6 +1926,21 @@ "node": ">= 0.6" } }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -2030,6 +2548,16 @@ "node": ">=8.10.0" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -2057,6 +2585,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -2083,6 +2621,57 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/sass": { + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.89.2.tgz", + "integrity": "sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/sass/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/sass/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -2162,6 +2751,19 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -2365,6 +2967,16 @@ "license": "MIT", "optional": true }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sprintf-js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", @@ -2431,8 +3043,8 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "devOptional": true, "license": "MIT", - "optional": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2446,8 +3058,8 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "devOptional": true, "license": "MIT", - "optional": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2569,6 +3181,23 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -2689,17 +3318,74 @@ "string-width": "^1.0.2 || 2 || 3 || 4" } }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } } } } diff --git a/package.json b/package.json index 26b954f..c6a6f5b 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,11 @@ "main": "server.js", "scripts": { "start": "node server.js", - "dev": "nodemon server.js" + "dev": "nodemon server.js", + "build-css": "sass src/scss/main.scss public/style.css --style=compressed", + "watch-css": "sass src/scss/main.scss public/style.css --watch", + "dev-with-css": "concurrently \"npm run watch-css\" \"npm run dev\"", + "build": "npm run build-css" }, "dependencies": { "cors": "^2.8.5", @@ -15,7 +19,9 @@ "sqlite3": "^5.1.6" }, "devDependencies": { - "nodemon": "^3.0.1" + "concurrently": "^9.2.0", + "nodemon": "^3.0.1", + "sass": "^1.89.2" }, "keywords": [ "ice", diff --git a/public/admin.html b/public/admin.html index c5b7820..0340851 100644 --- a/public/admin.html +++ b/public/admin.html @@ -7,313 +7,6 @@ -
@@ -363,26 +56,79 @@
-
-

All Location Reports

- - - - - - - - - - - - - - - - - -
IDStatusAddressDescriptionPersistentReportedActions
Loading...
+ +
+ + +
+ + +
+
+

All Location Reports

+ + + + + + + + + + + + + + + + + +
IDStatusAddressDescriptionPersistentReportedActions
Loading...
+
+
+ + +
+
+

🔒 Custom Profanity Words

+
+ + + + +
+ + + + + + + + + + + + + + + + + +
IDWordSeverityCategoryAddedActions
Loading...
+
+ +
+

🧪 Test Profanity Filter

+
+ + +
+
Enter text above to test profanity detection
+
diff --git a/public/style.css b/public/style.css index 31513ad..b80d961 100644 --- a/public/style.css +++ b/public/style.css @@ -1,595 +1 @@ -/* CSS Variables for theming */ -:root { - --bg-color: #f4f4f9; - --text-color: #333; - --card-bg: white; - --border-color: #ddd; - --input-bg: white; - --input-border: #ddd; - --button-bg: #007bff; - --button-hover: #0056b3; - --header-bg: transparent; - --footer-border: #ddd; - --table-header-bg: #f8f9fa; - --table-hover: #f8f9fa; - --toggle-bg: #f8f9fa; - --toggle-border: #dee2e6; - --toggle-active-bg: #007bff; - --shadow: rgba(0,0,0,0.1); -} - -/* Dark mode variables */ -[data-theme="dark"] { - --bg-color: #1a1a1a; - --text-color: #e0e0e0; - --card-bg: #2d2d2d; - --border-color: #404040; - --input-bg: #333; - --input-border: #555; - --button-bg: #4a90e2; - --button-hover: #357abd; - --header-bg: transparent; - --footer-border: #404040; - --table-header-bg: #3a3a3a; - --table-hover: #3a3a3a; - --toggle-bg: #404040; - --toggle-border: #555; - --toggle-active-bg: #4a90e2; - --shadow: rgba(0,0,0,0.3); -} - -/* Auto system theme detection */ -@media (prefers-color-scheme: dark) { - :root[data-theme="auto"] { - --bg-color: #1a1a1a; - --text-color: #e0e0e0; - --card-bg: #2d2d2d; - --border-color: #404040; - --input-bg: #333; - --input-border: #555; - --button-bg: #4a90e2; - --button-hover: #357abd; - --header-bg: transparent; - --footer-border: #404040; - --table-header-bg: #3a3a3a; - --table-hover: #3a3a3a; - --toggle-bg: #404040; - --toggle-border: #555; - --toggle-active-bg: #4a90e2; - --shadow: rgba(0,0,0,0.3); - } -} - -@media (prefers-color-scheme: light) { - :root[data-theme="auto"] { - --bg-color: #f4f4f9; - --text-color: #333; - --card-bg: white; - --border-color: #ddd; - --input-bg: white; - --input-border: #ddd; - --button-bg: #007bff; - --button-hover: #0056b3; - --header-bg: transparent; - --footer-border: #ddd; - --table-header-bg: #f8f9fa; - --table-hover: #f8f9fa; - --toggle-bg: #f8f9fa; - --toggle-border: #dee2e6; - --toggle-active-bg: #007bff; - --shadow: rgba(0,0,0,0.1); - } -} - -body { - font-family: Arial, sans-serif; - line-height: 1.6; - margin: 0; - padding: 0; - background-color: var(--bg-color); - color: var(--text-color); - transition: background-color 0.3s ease, color 0.3s ease; -} - -.container { - max-width: 1000px; - margin: 0 auto; - padding: 20px; -} - -header { - text-align: center; - padding-bottom: 20px; -} - -.map-section, .form-section { - margin-bottom: 20px; - padding: 15px; - background-color: var(--card-bg); - border-radius: 8px; - box-shadow: 0 2px 4px var(--shadow); - transition: background-color 0.3s ease; -} - -.map-section { - height: auto; - min-height: 650px; - padding-bottom: 20px; -} - -#map { - width: 100%; - height: 600px; - border-radius: 8px; - margin-bottom: 15px; -} - -.form-group { - margin-bottom: 10px; -} - -input[type="text"], textarea { - width: calc(100% - 20px); - padding: 8px; - margin-top: 5px; - border: 1px solid var(--input-border); - border-radius: 4px; - background-color: var(--input-bg); - color: var(--text-color); - transition: background-color 0.3s ease, border-color 0.3s ease; -} - -.autocomplete-container { - position: relative; - width: 100%; -} - -.autocomplete-list { - position: absolute; - top: 100%; - left: 0; - right: 0; - background: var(--card-bg); - border: 1px solid var(--border-color); - border-top: none; - border-radius: 0 0 4px 4px; - max-height: 200px; - overflow-y: auto; - z-index: 1000; - display: none; - box-shadow: 0 4px 6px var(--shadow); -} - -.autocomplete-item { - padding: 10px; - cursor: pointer; - border-bottom: 1px solid #eee; -} - -.autocomplete-item:hover, -.autocomplete-item.selected { - background-color: var(--table-hover); -} - -.autocomplete-item:last-child { - border-bottom: none; -} - -.input-help { - color: #666; - font-size: 0.85em; - margin-top: 4px; - display: block; -} - -button[type="submit"] { - background-color: var(--button-bg); - color: white; - border: none; - padding: 10px 20px; - cursor: pointer; - border-radius: 4px; - transition: background-color 0.2s ease-in; -} - -button[type="submit"]:hover { - background-color: var(--button-hover); -} - -.message { - margin-top: 10px; - padding: 10px; - display: none; - border-radius: 4px; -} - -.success { - background-color: #d4edda; - color: #155724; -} - -.error { - background-color: #f8d7da; - color: #721c24; -} - -/* Header layout for theme toggle */ -.header-content { - display: flex; - justify-content: space-between; - align-items: flex-start; - gap: 20px; -} - -.header-text { - flex: 1; -} - -/* Theme toggle button */ -.theme-toggle { - background: var(--card-bg); - border: 2px solid var(--border-color); - border-radius: 50%; - width: 50px; - height: 50px; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - transition: all 0.3s ease; - box-shadow: 0 2px 4px var(--shadow); - flex-shrink: 0; -} - -.theme-toggle:hover { - transform: scale(1.1); - box-shadow: 0 4px 8px var(--shadow); -} - -.theme-icon { - font-size: 20px; - transition: transform 0.3s ease; -} - -[data-theme="dark"] .theme-icon { - transform: rotate(180deg); -} - -footer { - text-align: center; - padding: 30px 20px; - margin-top: 30px; - border-top: 1px solid var(--footer-border); - clear: both; - transition: border-color 0.3s ease; -} - -.disclaimer { - font-size: 0.8em; - color: #777; -} - -/* Reports header and toggle */ -.reports-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 20px; -} - -.view-toggle { - display: flex; - gap: 10px; -} - -.toggle-btn { - background-color: var(--toggle-bg); - border: 2px solid var(--toggle-border); - color: var(--text-color); - padding: 8px 16px; - border-radius: 6px; - cursor: pointer; - font-size: 14px; - font-weight: 500; - transition: all 0.2s ease; -} - -.toggle-btn:hover { - opacity: 0.8; -} - -.toggle-btn.active { - background-color: var(--toggle-active-bg); - border-color: var(--toggle-active-bg); - color: white; -} - -.toggle-btn.active:hover { - opacity: 0.9; -} - -/* View containers */ -.view-container { - width: 100%; -} - -/* Table view styles */ -.table-container { - overflow-x: auto; - border-radius: 8px; - box-shadow: 0 2px 4px rgba(0,0,0,0.1); -} - -.reports-table { - width: 100%; - border-collapse: collapse; - background: var(--card-bg); - font-size: 14px; - transition: background-color 0.3s ease; -} - -.reports-table th { - background-color: var(--table-header-bg); - color: var(--text-color); - font-weight: 600; - padding: 12px; - text-align: left; - border-bottom: 2px solid var(--border-color); - position: sticky; - top: 0; - z-index: 10; -} - -.reports-table td { - padding: 12px; - border-bottom: 1px solid var(--border-color); - vertical-align: top; -} - -.reports-table tr:hover { - background-color: var(--table-hover); -} - -.reports-table tr:last-child td { - border-bottom: none; -} - -.table-controls { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 15px; -} - -.table-info { - color: #666; - font-size: 14px; -} - -/* Table cell specific styles */ -.location-cell { - font-weight: 500; - color: #495057; - max-width: 250px; -} - -.details-cell { - color: #6c757d; - font-style: italic; - max-width: 200px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.time-cell { - font-size: 12px; - color: #868e96; -} - -.remaining-cell { - font-weight: 500; - font-size: 12px; -} - -.remaining-cell.urgent { - color: #dc3545; - font-weight: 600; -} - -.remaining-cell.warning { - color: #fd7e14; - font-weight: 600; -} - -.remaining-cell.normal { - color: #28a745; -} - -/* Dark mode table cell overrides - ensure text is visible */ -[data-theme="dark"] .location-cell, -[data-theme="dark"] .details-cell, -[data-theme="dark"] .time-cell { - color: var(--text-color) !important; -} - -[data-theme="dark"] .remaining-cell { - color: var(--text-color) !important; -} - -/* Auto theme detection for dark mode */ -@media (prefers-color-scheme: dark) { - :root[data-theme="auto"] .location-cell, - :root[data-theme="auto"] .details-cell, - :root[data-theme="auto"] .time-cell { - color: var(--text-color) !important; - } - - :root[data-theme="auto"] .remaining-cell { - color: var(--text-color) !important; - } -} - -.loading { - text-align: center; - color: #6c757d; - font-style: italic; -} - -/* Responsive adjustments */ -@media (max-width: 768px) { - .container { - padding: 10px; - } - - .header-content { - flex-direction: column; - align-items: center; - gap: 15px; - } - - .header-text { - text-align: center; - } - - .theme-toggle { - align-self: center; - } - - header h1 { - font-size: 1.5em; - } - - header p { - font-size: 0.9em; - } - - .map-section, .form-section { - padding: 10px; - margin-bottom: 15px; - } - - #map { - height: 400px; - } - - .form-group { - margin-bottom: 15px; - } - - input[type="text"], textarea { - font-size: 16px; /* Prevents zoom on iOS */ - width: calc(100% - 16px); - padding: 12px 8px; - } - - button[type="submit"] { - width: 100%; - padding: 15px; - font-size: 16px; - } - - .reports-header { - flex-direction: column; - align-items: stretch; - gap: 15px; - text-align: center; - } - - .reports-header h2 { - font-size: 1.3em; - margin-bottom: 0; - } - - .view-toggle { - justify-content: center; - } - - .toggle-btn { - flex: 1; - font-size: 14px; - padding: 12px 8px; - } - - .reports-table { - font-size: 12px; - } - - .reports-table th, - .reports-table td { - padding: 8px 4px; - } - - .location-cell { - max-width: 120px; - font-size: 11px; - } - - .details-cell { - max-width: 100px; - font-size: 11px; - } - - .time-cell { - font-size: 10px; - } - - .remaining-cell { - font-size: 10px; - } - - .autocomplete-list { - max-height: 150px; - } - - .input-help { - font-size: 0.8em; - } - - footer { - padding: 20px 10px; - font-size: 0.9em; - } -} - -/* Extra small screens */ -@media (max-width: 480px) { - .container { - padding: 5px; - } - - header h1 { - font-size: 1.3em; - } - - .map-section, .form-section { - padding: 8px; - } - - #map { - height: 300px; - } - - .reports-table th { - font-size: 10px; - padding: 6px 2px; - } - - .reports-table td { - font-size: 10px; - padding: 6px 2px; - } - - .location-cell { - max-width: 100px; - } - - .details-cell { - max-width: 80px; - } - - .toggle-btn { - font-size: 12px; - padding: 10px 6px; - } -} +.admin-container{max-width:1200px;margin:0 auto;padding:24px}.login-section{background:var(--card-bg);color:var(--text-color);padding:32px;border-radius:8px;box-shadow:0 2px 4px rgba(0,0,0,.1);max-width:400px;margin:50px auto}.admin-section{display:none}.admin-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:24px}.header-buttons{display:flex;gap:8px;align-items:center}.header-btn{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:8px 16px;font-size:14px;background-color:#6c757d;color:#fff}.header-btn:hover{opacity:.9;transform:translateY(-1px)}.header-btn:active{transform:translateY(0)}.header-btn.btn-refresh{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:8px 16px;font-size:14px;background-color:#2196f3;color:#fff}.header-btn.btn-refresh:hover{opacity:.9;transform:translateY(-1px)}.header-btn.btn-refresh:active{transform:translateY(0)}.header-btn.btn-home{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:8px 16px;font-size:14px;background-color:#28a745;color:#fff}.header-btn.btn-home:hover{opacity:.9;transform:translateY(-1px)}.header-btn.btn-home:active{transform:translateY(0)}.header-btn.btn-logout{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:8px 16px;font-size:14px;background-color:#dc3545;color:#fff}.header-btn.btn-logout:hover{opacity:.9;transform:translateY(-1px)}.header-btn.btn-logout:active{transform:translateY(0)}.theme-toggle-admin{background:var(--card-bg) !important;color:var(--text-color) !important;border:2px solid var(--border-color) !important;width:40px;height:40px;border-radius:50% !important;display:flex;align-items:center;justify-content:center;padding:0 !important}.stats{display:grid;grid-template-columns:repeat(auto-fit, minmax(200px, 1fr));gap:24px;margin-bottom:24px}.stat-card{background:var(--card-bg);color:var(--text-color);padding:24px;border-radius:8px;box-shadow:0 2px 4px rgba(0,0,0,.1);text-align:center}.stat-number{font-size:2em;font-weight:bold;color:#2196f3}.locations-table{width:100%;border-collapse:collapse;background:var(--card-bg);color:var(--text-color);border-radius:8px;overflow:hidden;box-shadow:0 2px 4px rgba(0,0,0,.1);margin-top:24px}.locations-table th,.locations-table td{padding:8px 16px;text-align:left;border-bottom:1px solid var(--border-color);color:var(--text-color)}.locations-table th{background-color:var(--table-header-bg);font-weight:bold}.locations-table tr:hover{background-color:var(--table-hover)}.action-buttons{display:flex;gap:5px}.btn{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:4px 8px;font-size:12px;background-color:#2196f3;color:#fff}.btn:hover{opacity:.9;transform:translateY(-1px)}.btn:active{transform:translateY(0)}.btn-edit{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:4px 8px;font-size:12px;background-color:#2196f3;color:#fff}.btn-edit:hover{opacity:.9;transform:translateY(-1px)}.btn-edit:active{transform:translateY(0)}.btn-delete{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:4px 8px;font-size:12px;background-color:#dc3545;color:#fff}.btn-delete:hover{opacity:.9;transform:translateY(-1px)}.btn-delete:active{transform:translateY(0)}.btn-save{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:4px 8px;font-size:12px;background-color:#28a745;color:#fff}.btn-save:hover{opacity:.9;transform:translateY(-1px)}.btn-save:active{transform:translateY(0)}.btn-cancel{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:4px 8px;font-size:12px;background-color:#6c757d;color:#fff}.btn-cancel:hover{opacity:.9;transform:translateY(-1px)}.btn-cancel:active{transform:translateY(0)}.edit-row{background-color:#fff3cd !important}.edit-input{padding:8px 16px;border:1px solid var(--input-border);border-radius:4px;font-size:14px;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background-color:var(--input-bg);color:var(--text-color);transition:border-color .2s ease;width:100%;font-size:12px}.edit-input:focus{outline:none;border-color:#2196f3;box-shadow:0 0 0 2px rgba(33,150,243,.2)}.status-indicator{padding:4px 8px;border-radius:12px;font-size:12px;font-weight:bold;background-color:rgba(0,0,0,0);color:inherit}.status-active{padding:4px 8px;border-radius:12px;font-size:12px;font-weight:bold;background-color:#d4edda;color:#155724}.status-expired{padding:4px 8px;border-radius:12px;font-size:12px;font-weight:bold;background-color:#f8d7da;color:#721c24}.tab-navigation{display:flex;margin-bottom:24px;border-bottom:2px solid var(--border-color)}.tab-btn{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:8px 16px;font-size:14px;background-color:rgba(0,0,0,0);color:var(--text-color);border-bottom:3px solid rgba(0,0,0,0);border-radius:0}.tab-btn:hover{opacity:.9;transform:translateY(-1px)}.tab-btn:active{transform:translateY(0)}.tab-btn.active{border-bottom-color:#2196f3;color:#2196f3}.tab-btn:hover{background-color:var(--table-hover);transform:none}.tab-content{display:none}.tab-content.active{display:block}.profanity-management .management-section{background:var(--card-bg);color:var(--text-color);padding:24px;border-radius:8px;box-shadow:0 2px 4px rgba(0,0,0,.1);margin-bottom:24px}.profanity-management .management-section h4{margin-top:0;color:#2196f3}.profanity-management .profanity-form{display:grid;grid-template-columns:2fr 1fr 1fr auto;gap:8px;align-items:end;margin-bottom:24px}.profanity-management .profanity-form input,.profanity-management .profanity-form select{padding:8px 16px;border:1px solid var(--input-border);border-radius:4px;font-size:14px;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background-color:var(--input-bg);color:var(--text-color);transition:border-color .2s ease}.profanity-management .profanity-form input:focus,.profanity-management .profanity-form select:focus{outline:none;border-color:#2196f3;box-shadow:0 0 0 2px rgba(33,150,243,.2)}.profanity-management .test-section .test-form{display:grid;grid-template-columns:1fr auto;gap:8px;align-items:end}.profanity-management .test-section .test-form textarea{padding:8px 16px;border:1px solid var(--input-border);border-radius:4px;font-size:14px;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background-color:var(--input-bg);color:var(--text-color);transition:border-color .2s ease;resize:vertical;min-height:60px}.profanity-management .test-section .test-form textarea:focus{outline:none;border-color:#2196f3;box-shadow:0 0 0 2px rgba(33,150,243,.2)}.test-results{margin-top:16px;padding:16px;border-radius:4px}.test-results.profane{background-color:#f8d7da;color:#721c24;border:1px solid #f5c6cb}.test-results.clean{background-color:#d4edda;color:#155724;border:1px solid #c3e6cb}.test-results.empty{background-color:#f8f9fa;color:#6c757d;border:1px solid #dee2e6}.severity-low{padding:4px 8px;border-radius:12px;font-size:12px;font-weight:bold;background-color:#d1ecf1;color:#0c5460}.severity-medium{padding:4px 8px;border-radius:12px;font-size:12px;font-weight:bold;background-color:#fff3cd;color:#856404}.severity-high{padding:4px 8px;border-radius:12px;font-size:12px;font-weight:bold;background-color:#f8d7da;color:#721c24}.action-btn{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:4px 8px;font-size:12px;background-color:#2196f3;color:#fff}.action-btn:hover{opacity:.9;transform:translateY(-1px)}.action-btn:active{transform:translateY(0)}.action-btn.danger{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:4px 8px;font-size:12px;background-color:#dc3545;color:#fff}.action-btn.danger:hover{opacity:.9;transform:translateY(-1px)}.action-btn.danger:active{transform:translateY(0)}.persistent-toggle.active{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:8px 16px;font-size:14px;background-color:#ffc107;color:#000}.persistent-toggle.active:hover{opacity:.9;transform:translateY(-1px)}.persistent-toggle.active:active{transform:translateY(0)}.persistent-toggle.inactive{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:8px 16px;font-size:14px;background-color:#6c757d;color:#fff}.persistent-toggle.inactive:hover{opacity:.9;transform:translateY(-1px)}.persistent-toggle.inactive:active{transform:translateY(0)}@media(max-width: 768px){.admin-container{padding:16px}.admin-header{flex-direction:column;gap:16px;align-items:stretch}.header-buttons{justify-content:center;flex-wrap:wrap}.stats{grid-template-columns:1fr 1fr}.locations-table{font-size:12px}.locations-table th,.locations-table td{padding:4px 4px}.locations-table .address-cell{max-width:100px}.btn{padding:3px 4px;font-size:9px}.profanity-form{grid-template-columns:1fr;gap:8px}}:root{--background-color: #ffffff;--text-color: #333333;--card-bg: #f8f9fa;--border-color: #dee2e6;--input-bg: #ffffff;--input-border: #dee2e6;--table-header-bg: #e9ecef;--table-hover: #f5f5f5;--shadow: rgba(0, 0, 0, 0.1)}[data-theme=dark]{--background-color: #1a1a1a;--text-color: #ffffff;--card-bg: #2d2d2d;--border-color: #444444;--input-bg: #2d2d2d;--input-border: #444444;--table-header-bg: #3d3d3d;--table-hover: #3d3d3d;--shadow: rgba(0, 0, 0, 0.3)}*{margin:0;padding:0;box-sizing:border-box}body{font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background-color:var(--background-color);color:var(--text-color);line-height:1.6;min-height:100vh;transition:background-color .3s ease,color .3s ease}.form-group{margin-bottom:16px}.form-group label{display:block;margin-bottom:4px;font-weight:500}.form-group input,.form-group select,.form-group textarea{padding:8px 16px;border:1px solid var(--input-border);border-radius:4px;font-size:14px;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background-color:var(--input-bg);color:var(--text-color);transition:border-color .2s ease;width:100%}.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:#2196f3;box-shadow:0 0 0 2px rgba(33,150,243,.2)}button{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:8px 16px;font-size:14px;background-color:#2196f3;color:#fff}button:hover{opacity:.9;transform:translateY(-1px)}button:active{transform:translateY(0)}button:disabled{opacity:.6;cursor:not-allowed}.message{padding:16px;border-radius:4px;margin:16px 0;display:none}.message.error{background-color:#f8d7da;color:#721c24;border:1px solid #f5c6cb}.message.success{background-color:#d4edda;color:#155724;border:1px solid #c3e6cb}.message.info{background-color:#d1ecf1;color:#0c5460;border:1px solid #bee5eb}.theme-toggle{border:none;border-radius:4px;cursor:pointer;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;text-decoration:none;display:inline-block;transition:all .2s ease;padding:8px 16px;font-size:14px;background-color:rgba(0,0,0,0);color:#fff;border:2px solid var(--border-color);border-radius:50%;width:40px;height:40px;display:flex;align-items:center;justify-content:center}.theme-toggle:hover{opacity:.9;transform:translateY(-1px)}.theme-toggle:active{transform:translateY(0)}.theme-toggle:hover{background-color:var(--table-hover);transform:none}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.mb-sm{margin-bottom:8px}.mb-md{margin-bottom:16px}.mb-lg{margin-bottom:24px}.mt-sm{margin-top:8px}.mt-md{margin-top:16px}.mt-lg{margin-top:24px}.p-sm{padding:8px}.p-md{padding:16px}.p-lg{padding:24px}.d-flex{display:flex}.flex-center{display:flex;align-items:center;justify-content:center}.flex-between{display:flex;align-items:center;justify-content:space-between}.flex-column{display:flex;flex-direction:column}.w-100{width:100%}.h-100{height:100%}/*# sourceMappingURL=style.css.map */ diff --git a/public/style.css.map b/public/style.css.map new file mode 100644 index 0000000..8b4017e --- /dev/null +++ b/public/style.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../src/scss/pages/_admin.scss","../src/scss/_variables.scss","../src/scss/_mixins.scss","../src/scss/main.scss"],"names":[],"mappings":"AAKA,iBACE,iBACA,cACA,QCeW,KDZb,eE4BE,0BACA,wBACA,QDjBW,KCkBX,cDbiB,ICcjB,WDRU,yBDtBV,gBACA,iBAGF,eACE,aAIF,cEgCE,aACA,mBACA,8BFhCA,cCDW,KDIb,gBACE,aACA,ICRW,IDSX,mBAGF,YE5BE,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBASE,iBACA,UDoBW,KCjBb,iBFU2B,QET3B,MArBoD,KAuBpD,kBACE,WACA,2BAGF,mBACE,wBFGF,wBE/BA,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBASE,iBACA,UDoBW,KCjBb,iBDvBc,QCwBd,MArBoD,KAuBpD,8BACE,WACA,2BAGF,+BACE,wBFOF,qBEnCA,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBASE,iBACA,UDoBW,KCjBb,iBDrBc,QCsBd,MArBoD,KAuBpD,2BACE,WACA,2BAGF,4BACE,wBFWF,uBEvCA,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBASE,iBACA,UDoBW,KCjBb,iBDnBa,QCoBb,MArBoD,KAuBpD,6BACE,WACA,2BAGF,8BACE,wBFgBJ,oBACE,qCACA,mCACA,gDACA,WACA,YACA,6BEPA,aACA,mBACA,uBFOA,qBAIF,OACE,aACA,2DACA,ICzCW,KD0CX,cC1CW,KD6Cb,WE7BE,0BACA,wBACA,QDlBW,KCmBX,cDbiB,ICcjB,WDRU,yBDmCV,kBAGF,aACE,cACA,iBACA,MC3Ec,QD+EhB,iBEdE,WACA,yBACA,0BACA,wBACA,cDzCiB,IC0CjB,gBACA,WDrCU,yBD+CV,WC3DW,KCmDX,wCACE,iBACA,gBACA,4CACA,wBAGF,oBACE,wCACA,iBAGF,0BACE,oCFDJ,gBACE,aACA,QAGF,KEtFE,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBAGE,gBACA,UDyBW,KChBb,iBDvBc,QCwBd,MArBoD,KAuBpD,WACE,WACA,2BAGF,YACE,wBF6DF,UEzFA,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBAGE,gBACA,UDyBW,KChBb,iBDvBc,QCwBd,MArBoD,KAuBpD,gBACE,WACA,2BAGF,iBACE,wBFiEF,YE7FA,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBAGE,gBACA,UDyBW,KChBb,iBDnBa,QCoBb,MArBoD,KAuBpD,kBACE,WACA,2BAGF,mBACE,wBFqEF,UEjGA,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBAGE,gBACA,UDyBW,KChBb,iBDrBc,QCsBd,MArBoD,KAuBpD,gBACE,WACA,2BAGF,iBACE,wBFyEF,YErGA,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBAGE,gBACA,UDyBW,KChBb,iBFmF6B,QElF7B,MArBoD,KAuBpD,kBACE,WACA,2BAGF,mBACE,wBF+EJ,UACE,oCAGF,YEvBE,iBACA,qCACA,cDnEiB,ICoEjB,UDvDa,KCwDb,YD1DY,wEC2DZ,iCACA,wBACA,iCFkBA,WACA,UC/Ea,KC8Db,kBACE,aACA,aDvGY,QCwGZ,yCFkBJ,kBEZE,gBACA,cDlFiB,KCmFjB,UDzEa,KC0Eb,iBACA,iBFS0B,cER1B,MFQuC,QAGzC,eEhBE,gBACA,cDlFiB,KCmFjB,UDzEa,KC0Eb,iBACA,iBFa0B,QEZ1B,MFYmC,QAGrC,gBEpBE,gBACA,cDlFiB,KCmFjB,UDzEa,KC0Eb,iBACA,iBFiB0B,QEhB1B,MFgBmC,QAIrC,gBACE,aACA,cCnHW,KDoHX,4CAGF,SEzIE,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBASE,iBACA,UDoBW,KCjBb,iBFuH2B,cEtH3B,MFsHqD,kBACrD,sCACA,gBEtHA,eACE,WACA,2BAGF,gBACE,wBFkHF,gBACE,oBCnJY,QDoJZ,MCpJY,QDuJd,eACE,oCACA,eAIJ,aACE,aAEA,oBACE,cAMF,0CEjIA,0BACA,wBACA,QDlBW,KCmBX,cDbiB,ICcjB,WDRU,yBDuIR,cCnJS,KDqJT,6CACE,aACA,MC7KU,QDiLd,sCACE,aACA,uCACA,IChKS,IDiKT,gBACA,cChKS,KDkKT,yFE5FF,iBACA,qCACA,cDnEiB,ICoEjB,UDvDa,KCwDb,YD1DY,wEC2DZ,iCACA,wBACA,iCAEA,qGACE,aACA,aDvGY,QCwGZ,yCFsFA,+CACE,aACA,+BACA,IC7KO,ID8KP,gBAEA,wDExGJ,iBACA,qCACA,cDnEiB,ICoEjB,UDvDa,KCwDb,YD1DY,wEC2DZ,iCACA,wBACA,iCFmGM,gBACA,gBElGN,8DACE,aACA,aDvGY,QCwGZ,yCFqGJ,cACE,WCzLW,KD0LX,QC1LW,KD2LX,cCrLiB,IDuLjB,sBACE,yBACA,cACA,yBAGF,oBACE,yBACA,cACA,yBAGF,oBACE,yBACA,cACA,yBAIJ,cEvHE,gBACA,cDlFiB,KCmFjB,UDzEa,KC0Eb,iBACA,iBFoH0B,QEnH1B,MFmHmC,QAGrC,iBE3HE,gBACA,cDlFiB,KCmFjB,UDzEa,KC0Eb,iBACA,iBFwH0B,QEvH1B,MFuHmC,QAGrC,eE/HE,gBACA,cDlFiB,KCmFjB,UDzEa,KC0Eb,iBACA,iBF4H0B,QE3H1B,MF2HmC,QAGrC,YE7OE,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBAGE,gBACA,UDyBW,KChBb,iBDvBc,QCwBd,MArBoD,KAuBpD,kBACE,WACA,2BAGF,mBACE,wBFoNF,mBEhPA,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBAGE,gBACA,UDyBW,KChBb,iBDnBa,QCoBb,MArBoD,KAuBpD,yBACE,WACA,2BAGF,0BACE,wBF2NF,0BEvPA,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBASE,iBACA,UDoBW,KCjBb,iBDpBc,QCqBd,MFoO0D,KElO1D,gCACE,WACA,2BAGF,iCACE,wBF+NF,4BE3PA,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBASE,iBACA,UDoBW,KCjBb,iBFyO6B,QExO7B,MArBoD,KAuBpD,kCACE,WACA,2BAGF,mCACE,wBAwFF,yBF8IA,iBACE,QClPS,KDqPX,cACE,sBACA,ICvPS,KDwPT,oBAGF,gBACE,uBACA,eAGF,OACE,8BAGF,iBACE,UCnPW,KDqPX,wCACE,gBAGF,+BACE,gBAIJ,KACE,gBACA,cAGF,gBACE,0BACA,ICxRS,KEZb,MAEE,4BACA,sBACA,mBACA,wBACA,oBACA,wBACA,2BACA,uBACA,6BAGF,kBAEE,4BACA,sBACA,mBACA,wBACA,oBACA,wBACA,2BACA,uBACA,6BAGF,EACE,SACA,UACA,sBAGF,KACE,YFHY,wEEIZ,yCACA,wBACA,gBACA,iBACA,oDAIF,YACE,cF9BW,KEgCX,kBACE,cACA,cFpCS,IEqCT,gBAGF,0DDiCA,iBACA,qCACA,cDnEiB,ICoEjB,UDvDa,KCwDb,YD1DY,wEC2DZ,iCACA,wBACA,iCCtCE,WDwCF,4EACE,aACA,aDvGY,QCwGZ,yCCvCJ,OD7DE,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBASE,iBACA,UDoBW,KCjBb,iBDvBc,QCwBd,MArBoD,KAuBpD,aACE,WACA,2BAGF,cACE,wBCoCF,gBACE,WACA,mBAKJ,SACE,QFvDW,KEwDX,cFlDiB,IEmDjB,cACA,aAEA,eACE,yBACA,cACA,yBAGF,iBACE,yBACA,cACA,yBAGF,cACE,yBACA,cACA,yBAOJ,cDnGE,YACA,cDsBiB,ICrBjB,eACA,YD+BY,wEC9BZ,qBACA,qBACA,wBASE,iBACA,UDoBW,KCjBb,iBCiF2B,cDhF3B,MArBoD,KCsGpD,qCACA,cF5EmB,IE6EnB,WACA,YD7DA,aACA,mBACA,uBAvBA,oBACE,WACA,2BAGF,qBACE,wBC+EF,oBACE,oCACA,eAKJ,+BACA,2BACA,6BAEA,qBFtGa,IEuGb,qBFtGa,KEuGb,qBFtGa,KEwGb,kBF1Ga,IE2Gb,kBF1Ga,KE2Gb,kBF1Ga,KE4Gb,cF9Ga,IE+Gb,cF9Ga,KE+Gb,cF9Ga,KEgHb,qBACA,aDxFE,aACA,mBACA,uBCuFF,cDnFE,aACA,mBACA,8BCkFF,aD9EE,aACA,sBC+EF,kBACA","file":"style.css"} \ No newline at end of file diff --git a/src/scss/_mixins.scss b/src/scss/_mixins.scss new file mode 100644 index 0000000..e0e95f6 --- /dev/null +++ b/src/scss/_mixins.scss @@ -0,0 +1,137 @@ +// Import variables +@use 'variables' as *; + +// Button mixin +@mixin button($bg-color: $primary-color, $text-color: white, $size: md) { + border: none; + border-radius: $border-radius-sm; + cursor: pointer; + font-family: $font-family; + text-decoration: none; + display: inline-block; + transition: all 0.2s ease; + + @if $size == sm { + padding: $spacing-xs $spacing-sm; + font-size: $font-size-sm; + } @else if $size == lg { + padding: $spacing-md $spacing-lg; + font-size: $font-size-lg; + } @else { + padding: $spacing-sm $spacing-md; + font-size: $font-size-md; + } + + background-color: $bg-color; + color: $text-color; + + &:hover { + opacity: 0.9; + transform: translateY(-1px); + } + + &:active { + transform: translateY(0); + } +} + +// Card mixin +@mixin card($padding: $spacing-lg) { + background: var(--card-bg); + color: var(--text-color); + padding: $padding; + border-radius: $border-radius-md; + box-shadow: $shadow-md; +} + +// Flex layout mixins +@mixin flex-center { + display: flex; + align-items: center; + justify-content: center; +} + +@mixin flex-between { + display: flex; + align-items: center; + justify-content: space-between; +} + +@mixin flex-column { + display: flex; + flex-direction: column; +} + +// Table styling mixin +@mixin table-base { + width: 100%; + border-collapse: collapse; + background: var(--card-bg); + color: var(--text-color); + border-radius: $border-radius-md; + overflow: hidden; + box-shadow: $shadow-md; + + th, td { + padding: $spacing-sm $spacing-md; + text-align: left; + border-bottom: 1px solid var(--border-color); + color: var(--text-color); + } + + th { + background-color: var(--table-header-bg); + font-weight: bold; + } + + tr:hover { + background-color: var(--table-hover); + } +} + +// Form input mixin +@mixin input-base { + padding: $spacing-sm $spacing-md; + border: 1px solid var(--input-border); + border-radius: $border-radius-sm; + font-size: $font-size-md; + font-family: $font-family; + background-color: var(--input-bg); + color: var(--text-color); + transition: border-color 0.2s ease; + + &:focus { + outline: none; + border-color: $primary-color; + box-shadow: 0 0 0 2px rgba($primary-color, 0.2); + } +} + +// Status indicator mixin +@mixin status-indicator($bg-color, $text-color) { + padding: $spacing-xs $spacing-sm; + border-radius: $border-radius-lg; + font-size: $font-size-sm; + font-weight: bold; + background-color: $bg-color; + color: $text-color; +} + +// Responsive breakpoint mixins +@mixin mobile { + @media (max-width: $mobile) { + @content; + } +} + +@mixin tablet { + @media (max-width: $tablet) { + @content; + } +} + +@mixin desktop { + @media (min-width: $desktop) { + @content; + } +} diff --git a/src/scss/_variables.scss b/src/scss/_variables.scss new file mode 100644 index 0000000..5fec122 --- /dev/null +++ b/src/scss/_variables.scss @@ -0,0 +1,55 @@ +// Color Palette +$primary-color: #2196F3; +$secondary-color: #1976D2; +$success-color: #28a745; +$warning-color: #ffc107; +$danger-color: #dc3545; +$info-color: #17a2b8; + +// Theme Colors (CSS Variables will be generated) +$light-bg: #ffffff; +$light-text: #333333; +$light-card-bg: #f8f9fa; +$light-border: #dee2e6; + +$dark-bg: #1a1a1a; +$dark-text: #ffffff; +$dark-card-bg: #2d2d2d; +$dark-border: #444444; + +// Spacing +$spacing-xs: 4px; +$spacing-sm: 8px; +$spacing-md: 16px; +$spacing-lg: 24px; +$spacing-xl: 32px; +$spacing-xxl: 48px; + +// Border Radius +$border-radius-sm: 4px; +$border-radius-md: 8px; +$border-radius-lg: 12px; +$border-radius-full: 50%; + +// Shadows +$shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1); +$shadow-md: 0 2px 4px rgba(0, 0, 0, 0.1); +$shadow-lg: 0 4px 8px rgba(0, 0, 0, 0.15); + +// Typography +$font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; +$font-size-sm: 12px; +$font-size-md: 14px; +$font-size-lg: 16px; +$font-size-xl: 18px; +$font-size-xxl: 24px; + +// Z-Index +$z-index-modal: 1000; +$z-index-dropdown: 100; +$z-index-tooltip: 200; + +// Breakpoints +$mobile: 768px; +$tablet: 1024px; +$desktop: 1200px; diff --git a/src/scss/main.scss b/src/scss/main.scss new file mode 100644 index 0000000..99567a2 --- /dev/null +++ b/src/scss/main.scss @@ -0,0 +1,142 @@ +// Import variables and mixins first +@use 'variables' as *; +@use 'mixins' as *; +@use 'pages/admin'; + +// Import existing styles from style.css (converted to SCSS) +// We'll keep the existing theme variables and base styles + +// Base styles and theme variables (from existing style.css) +:root { + /* Light theme (default) */ + --background-color: #{$light-bg}; + --text-color: #{$light-text}; + --card-bg: #{$light-card-bg}; + --border-color: #{$light-border}; + --input-bg: #{$light-bg}; + --input-border: #{$light-border}; + --table-header-bg: #e9ecef; + --table-hover: #f5f5f5; + --shadow: rgba(0, 0, 0, 0.1); +} + +[data-theme="dark"] { + /* Dark theme */ + --background-color: #{$dark-bg}; + --text-color: #{$dark-text}; + --card-bg: #{$dark-card-bg}; + --border-color: #{$dark-border}; + --input-bg: #{$dark-card-bg}; + --input-border: #{$dark-border}; + --table-header-bg: #3d3d3d; + --table-hover: #3d3d3d; + --shadow: rgba(0, 0, 0, 0.3); +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: $font-family; + background-color: var(--background-color); + color: var(--text-color); + line-height: 1.6; + min-height: 100vh; + transition: background-color 0.3s ease, color 0.3s ease; +} + +// Base form styles +.form-group { + margin-bottom: $spacing-md; + + label { + display: block; + margin-bottom: $spacing-xs; + font-weight: 500; + } + + input, select, textarea { + @include input-base; + width: 100%; + } +} + +button { + @include button; + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + } +} + +// Message styles +.message { + padding: $spacing-md; + border-radius: $border-radius-sm; + margin: $spacing-md 0; + display: none; + + &.error { + background-color: #f8d7da; + color: #721c24; + border: 1px solid #f5c6cb; + } + + &.success { + background-color: #d4edda; + color: #155724; + border: 1px solid #c3e6cb; + } + + &.info { + background-color: #d1ecf1; + color: #0c5460; + border: 1px solid #bee5eb; + } +} + +// Page-specific styles are imported at the top with other @use statements + +// Theme toggle styles (common across pages) +.theme-toggle { + @include button($bg-color: transparent); + border: 2px solid var(--border-color); + border-radius: $border-radius-full; + width: 40px; + height: 40px; + @include flex-center; + + &:hover { + background-color: var(--table-hover); + transform: none; + } +} + +// Utility classes +.text-center { text-align: center; } +.text-left { text-align: left; } +.text-right { text-align: right; } + +.mb-sm { margin-bottom: $spacing-sm; } +.mb-md { margin-bottom: $spacing-md; } +.mb-lg { margin-bottom: $spacing-lg; } + +.mt-sm { margin-top: $spacing-sm; } +.mt-md { margin-top: $spacing-md; } +.mt-lg { margin-top: $spacing-lg; } + +.p-sm { padding: $spacing-sm; } +.p-md { padding: $spacing-md; } +.p-lg { padding: $spacing-lg; } + +.d-flex { display: flex; } +.flex-center { @include flex-center; } +.flex-between { @include flex-between; } +.flex-column { @include flex-column; } + +.w-100 { width: 100%; } +.h-100 { height: 100%; } diff --git a/src/scss/pages/_admin.scss b/src/scss/pages/_admin.scss new file mode 100644 index 0000000..73b9e05 --- /dev/null +++ b/src/scss/pages/_admin.scss @@ -0,0 +1,304 @@ +// Import variables and mixins +@use '../variables' as *; +@use '../mixins' as *; + +// Admin Page Styles +.admin-container { + max-width: 1200px; + margin: 0 auto; + padding: $spacing-lg; +} + +.login-section { + @include card($spacing-xl); + max-width: 400px; + margin: 50px auto; +} + +.admin-section { + display: none; +} + +// Admin Header +.admin-header { + @include flex-between; + margin-bottom: $spacing-lg; +} + +.header-buttons { + display: flex; + gap: $spacing-sm; + align-items: center; +} + +.header-btn { + @include button($bg-color: #6c757d); + + &.btn-refresh { + @include button($bg-color: $primary-color); + } + + &.btn-home { + @include button($bg-color: $success-color); + } + + &.btn-logout { + @include button($bg-color: $danger-color); + } +} + +.theme-toggle-admin { + background: var(--card-bg) !important; + color: var(--text-color) !important; + border: 2px solid var(--border-color) !important; + width: 40px; + height: 40px; + border-radius: $border-radius-full !important; + @include flex-center; + padding: 0 !important; +} + +// Stats Cards +.stats { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: $spacing-lg; + margin-bottom: $spacing-lg; +} + +.stat-card { + @include card; + text-align: center; +} + +.stat-number { + font-size: 2em; + font-weight: bold; + color: $primary-color; +} + +// Tables +.locations-table { + @include table-base; + margin-top: $spacing-lg; +} + +// Buttons +.action-buttons { + display: flex; + gap: 5px; +} + +.btn { + @include button($size: sm); + + &-edit { + @include button($bg-color: $primary-color, $size: sm); + } + + &-delete { + @include button($bg-color: $danger-color, $size: sm); + } + + &-save { + @include button($bg-color: $success-color, $size: sm); + } + + &-cancel { + @include button($bg-color: #6c757d, $size: sm); + } +} + +// Edit State +.edit-row { + background-color: #fff3cd !important; +} + +.edit-input { + @include input-base; + width: 100%; + font-size: $font-size-sm; +} + +// Status Indicators +.status-indicator { + @include status-indicator(transparent, inherit); +} + +.status-active { + @include status-indicator(#d4edda, #155724); +} + +.status-expired { + @include status-indicator(#f8d7da, #721c24); +} + +// Tabs +.tab-navigation { + display: flex; + margin-bottom: $spacing-lg; + border-bottom: 2px solid var(--border-color); +} + +.tab-btn { + @include button($bg-color: transparent, $text-color: var(--text-color)); + border-bottom: 3px solid transparent; + border-radius: 0; + + &.active { + border-bottom-color: $primary-color; + color: $primary-color; + } + + &:hover { + background-color: var(--table-hover); + transform: none; + } +} + +.tab-content { + display: none; + + &.active { + display: block; + } +} + +// Profanity Management +.profanity-management { + .management-section { + @include card; + margin-bottom: $spacing-lg; + + h4 { + margin-top: 0; + color: $primary-color; + } + } + + .profanity-form { + display: grid; + grid-template-columns: 2fr 1fr 1fr auto; + gap: $spacing-sm; + align-items: end; + margin-bottom: $spacing-lg; + + input, select { + @include input-base; + } + } + + .test-section { + .test-form { + display: grid; + grid-template-columns: 1fr auto; + gap: $spacing-sm; + align-items: end; + + textarea { + @include input-base; + resize: vertical; + min-height: 60px; + } + } + } +} + +.test-results { + margin-top: $spacing-md; + padding: $spacing-md; + border-radius: $border-radius-sm; + + &.profane { + background-color: #f8d7da; + color: #721c24; + border: 1px solid #f5c6cb; + } + + &.clean { + background-color: #d4edda; + color: #155724; + border: 1px solid #c3e6cb; + } + + &.empty { + background-color: #f8f9fa; + color: #6c757d; + border: 1px solid #dee2e6; + } +} + +.severity-low { + @include status-indicator(#d1ecf1, #0c5460); +} + +.severity-medium { + @include status-indicator(#fff3cd, #856404); +} + +.severity-high { + @include status-indicator(#f8d7da, #721c24); +} + +.action-btn { + @include button($size: sm); + + &.danger { + @include button($bg-color: $danger-color, $size: sm); + } +} + +// Persistent Toggle +.persistent-toggle { + &.active { + @include button($bg-color: $warning-color, $text-color: #000); + } + + &.inactive { + @include button($bg-color: #6c757d); + } +} + +// Responsive Design +@include mobile { + .admin-container { + padding: $spacing-md; + } + + .admin-header { + flex-direction: column; + gap: $spacing-md; + align-items: stretch; + } + + .header-buttons { + justify-content: center; + flex-wrap: wrap; + } + + .stats { + grid-template-columns: 1fr 1fr; + } + + .locations-table { + font-size: $font-size-sm; + + th, td { + padding: $spacing-xs $spacing-xs; + } + + .address-cell { + max-width: 100px; + } + } + + .btn { + padding: 3px 4px; + font-size: 9px; + } + + .profanity-form { + grid-template-columns: 1fr; + gap: $spacing-sm; + } +}