mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-25 06:04:54 +00:00
Generated by Spark: Any non standard material UI CSS uses sass
This commit is contained in:
7
PRD.md
7
PRD.md
@@ -96,6 +96,13 @@ This is a full-featured low-code IDE with multiple integrated tools (code editor
|
||||
- **Progression**: User finalizes design → Clicks export → System bundles files → Downloads zip or shows code → User extracts and runs locally
|
||||
- **Success criteria**: Generated project structure is valid; includes package.json; code runs without errors
|
||||
|
||||
### Custom Sass Styling System
|
||||
- **Functionality**: Comprehensive Sass-based styling system for non-standard Material UI components with pre-built components, utilities, mixins, and animations
|
||||
- **Purpose**: Extend Material UI with custom styled components and provide consistent design patterns through Sass
|
||||
- **Trigger**: Using Sass classes in components or importing Sass modules for custom styling
|
||||
- **Progression**: Import main.scss → Apply custom component classes → Use mixins for custom styles → Configure variables for theming
|
||||
- **Success criteria**: All Sass styles compile correctly; custom components render with proper styling; mixins work as expected; animations are smooth and respect reduced motion preferences
|
||||
|
||||
## Edge Case Handling
|
||||
- **Empty Projects**: Show welcome screen with quick-start templates when no project exists; AI can generate entire projects from scratch
|
||||
- **Invalid Prisma Schemas**: Validate models and show inline errors before generating code
|
||||
|
||||
@@ -15,6 +15,7 @@ A comprehensive visual low-code platform for generating production-ready Next.js
|
||||
- **Prisma Schema Designer** - Visual database model builder with relations and field configuration
|
||||
- **Component Tree Builder** - Hierarchical React component designer with Material UI integration
|
||||
- **Theme Designer** - Advanced theming with multiple variants (light/dark/custom) and unlimited custom colors
|
||||
- **Sass Styling System** - Custom Material UI components with Sass, including utilities, mixins, and animations
|
||||
- **Flask Backend Designer** - Python REST API designer with blueprints, endpoints, and CORS configuration
|
||||
- **Project Settings** - Configure Next.js options, npm packages, scripts, and build settings
|
||||
|
||||
@@ -58,6 +59,7 @@ A comprehensive visual low-code platform for generating production-ready Next.js
|
||||
- Next.js 14 with App Router
|
||||
- React 18 with TypeScript
|
||||
- Material UI 5
|
||||
- Sass/SCSS for custom styling
|
||||
- Monaco Editor
|
||||
- Tailwind CSS
|
||||
- Framer Motion
|
||||
@@ -81,6 +83,7 @@ The application includes comprehensive built-in documentation:
|
||||
- **README** - Complete feature overview and getting started guide
|
||||
- **Roadmap** - Completed features and planned enhancements
|
||||
- **Agents Files** - AI service architecture and integration points
|
||||
- **Sass Styles Guide** - Custom Material UI components, utilities, mixins, and animations
|
||||
|
||||
Access documentation by clicking the **Documentation** tab in the application.
|
||||
|
||||
@@ -95,6 +98,7 @@ Access documentation by clicking the **Documentation** tab in the application.
|
||||
- Auto error detection and repair
|
||||
- Flask backend designer
|
||||
- Project settings and npm management
|
||||
- Custom Sass styling system with utilities and mixins
|
||||
|
||||
### 🔮 Planned
|
||||
- Real-time preview with hot reload
|
||||
|
||||
362
package-lock.json
generated
362
package-lock.json
generated
@@ -63,6 +63,7 @@
|
||||
"react-hook-form": "^7.54.2",
|
||||
"react-resizable-panels": "^2.1.7",
|
||||
"recharts": "^2.15.1",
|
||||
"sass": "^1.97.2",
|
||||
"sonner": "^2.0.1",
|
||||
"tailwind-merge": "^3.0.2",
|
||||
"three": "^0.175.0",
|
||||
@@ -1479,6 +1480,302 @@
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher": {
|
||||
"version": "2.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.4.tgz",
|
||||
"integrity": "sha512-WYa2tUVV5HiArWPB3ydlOc4R2ivq0IDrlqhMi3l7mVsFEXNcTfxYFPIHXHXIh/ca/y/V5N4E1zecyxdIBjYnkQ==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.3",
|
||||
"is-glob": "^4.0.3",
|
||||
"node-addon-api": "^7.0.0",
|
||||
"picomatch": "^4.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@parcel/watcher-android-arm64": "2.5.4",
|
||||
"@parcel/watcher-darwin-arm64": "2.5.4",
|
||||
"@parcel/watcher-darwin-x64": "2.5.4",
|
||||
"@parcel/watcher-freebsd-x64": "2.5.4",
|
||||
"@parcel/watcher-linux-arm-glibc": "2.5.4",
|
||||
"@parcel/watcher-linux-arm-musl": "2.5.4",
|
||||
"@parcel/watcher-linux-arm64-glibc": "2.5.4",
|
||||
"@parcel/watcher-linux-arm64-musl": "2.5.4",
|
||||
"@parcel/watcher-linux-x64-glibc": "2.5.4",
|
||||
"@parcel/watcher-linux-x64-musl": "2.5.4",
|
||||
"@parcel/watcher-win32-arm64": "2.5.4",
|
||||
"@parcel/watcher-win32-ia32": "2.5.4",
|
||||
"@parcel/watcher-win32-x64": "2.5.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-android-arm64": {
|
||||
"version": "2.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.4.tgz",
|
||||
"integrity": "sha512-hoh0vx4v+b3BNI7Cjoy2/B0ARqcwVNrzN/n7DLq9ZB4I3lrsvhrkCViJyfTj/Qi5xM9YFiH4AmHGK6pgH1ss7g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"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.4",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.4.tgz",
|
||||
"integrity": "sha512-kphKy377pZiWpAOyTgQYPE5/XEKVMaj6VUjKT5VkNyUJlr2qZAn8gIc7CPzx+kbhvqHDT9d7EqdOqRXT6vk0zw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"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.4",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.4.tgz",
|
||||
"integrity": "sha512-UKaQFhCtNJW1A9YyVz3Ju7ydf6QgrpNQfRZ35wNKUhTQ3dxJ/3MULXN5JN/0Z80V/KUBDGa3RZaKq1EQT2a2gg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"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.4",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.4.tgz",
|
||||
"integrity": "sha512-Dib0Wv3Ow/m2/ttvLdeI2DBXloO7t3Z0oCp4bAb2aqyqOjKPPGrg10pMJJAQ7tt8P4V2rwYwywkDhUia/FgS+Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"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.4",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.4.tgz",
|
||||
"integrity": "sha512-I5Vb769pdf7Q7Sf4KNy8Pogl/URRCKu9ImMmnVKYayhynuyGYMzuI4UOWnegQNa2sGpsPSbzDsqbHNMyeyPCgw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"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.4",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.4.tgz",
|
||||
"integrity": "sha512-kGO8RPvVrcAotV4QcWh8kZuHr9bXi9a3bSZw7kFarYR0+fGliU7hd/zevhjw8fnvIKG3J9EO5G6sXNGCSNMYPQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"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.4",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.4.tgz",
|
||||
"integrity": "sha512-KU75aooXhqGFY2W5/p8DYYHt4hrjHZod8AhcGAmhzPn/etTa+lYCDB2b1sJy3sWJ8ahFVTdy+EbqSBvMx3iFlw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"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.4",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.4.tgz",
|
||||
"integrity": "sha512-Qx8uNiIekVutnzbVdrgSanM+cbpDD3boB1f8vMtnuG5Zau4/bdDbXyKwIn0ToqFhIuob73bcxV9NwRm04/hzHQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"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.4",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.4.tgz",
|
||||
"integrity": "sha512-UYBQvhYmgAv61LNUn24qGQdjtycFBKSK3EXr72DbJqX9aaLbtCOO8+1SkKhD/GNiJ97ExgcHBrukcYhVjrnogA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"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.4",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.4.tgz",
|
||||
"integrity": "sha512-YoRWCVgxv8akZrMhdyVi6/TyoeeMkQ0PGGOf2E4omODrvd1wxniXP+DBynKoHryStks7l+fDAMUBRzqNHrVOpg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"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.4",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.4.tgz",
|
||||
"integrity": "sha512-iby+D/YNXWkiQNYcIhg8P5hSjzXEHaQrk2SLrWOUD7VeC4Ohu0WQvmV+HDJokZVJ2UjJ4AGXW3bx7Lls9Ln4TQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"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.4",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.4.tgz",
|
||||
"integrity": "sha512-vQN+KIReG0a2ZDpVv8cgddlf67J8hk1WfZMMP7sMeZmJRSmEax5xNDNWKdgqSe2brOKTQQAs3aCCUal2qBHAyg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"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.4",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.4.tgz",
|
||||
"integrity": "sha512-3A6efb6BOKwyw7yk9ro2vus2YTt2nvcd56AuzxdMiVOxL9umDyN5PKkKfZ/gZ9row41SjVmTVQNWQhaRRGpOKw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@phosphor-icons/react": {
|
||||
"version": "2.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@phosphor-icons/react/-/react-2.1.10.tgz",
|
||||
@@ -5247,6 +5544,21 @@
|
||||
"node": ">= 16"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"readdirp": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.16.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/class-variance-authority": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
|
||||
@@ -7238,6 +7550,12 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "5.1.4",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
|
||||
"integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
|
||||
@@ -7329,7 +7647,7 @@
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
@@ -7339,7 +7657,7 @@
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
@@ -8084,6 +8402,13 @@
|
||||
"react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
|
||||
}
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
|
||||
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/nwsapi": {
|
||||
"version": "2.2.23",
|
||||
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz",
|
||||
@@ -8733,6 +9058,19 @@
|
||||
"react-dom": ">=16.6.0"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/recharts": {
|
||||
"version": "2.15.4",
|
||||
"resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz",
|
||||
@@ -8987,6 +9325,26 @@
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.97.2",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.97.2.tgz",
|
||||
"integrity": "sha512-y5LWb0IlbO4e97Zr7c3mlpabcbBtS+ieiZ9iwDooShpFKWXf62zz5pEPdwrLYm+Bxn1fnbwFGzHuCLSA9tBmrw==",
|
||||
"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/saxes": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
"react-hook-form": "^7.54.2",
|
||||
"react-resizable-panels": "^2.1.7",
|
||||
"recharts": "^2.15.1",
|
||||
"sass": "^1.97.2",
|
||||
"sonner": "^2.0.1",
|
||||
"tailwind-merge": "^3.0.2",
|
||||
"three": "^0.175.0",
|
||||
|
||||
@@ -20,6 +20,7 @@ import { FlaskDesigner } from '@/components/FlaskDesigner'
|
||||
import { ProjectSettingsDesigner } from '@/components/ProjectSettingsDesigner'
|
||||
import { ErrorPanel } from '@/components/ErrorPanel'
|
||||
import { DocumentationView } from '@/components/DocumentationView'
|
||||
import { SassStylesShowcase } from '@/components/SassStylesShowcase'
|
||||
import { generateNextJSProject, generatePrismaSchema, generateMUITheme, generatePlaywrightTests, generateStorybookStories, generateUnitTests, generateFlaskApp } from '@/lib/generators'
|
||||
import { AIService } from '@/lib/ai-service'
|
||||
import { toast } from 'sonner'
|
||||
@@ -350,6 +351,10 @@ function App() {
|
||||
<FileText size={18} />
|
||||
Documentation
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="sass" className="gap-2">
|
||||
<PaintBrush size={18} />
|
||||
Sass Styles
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
|
||||
@@ -428,6 +433,10 @@ function App() {
|
||||
<TabsContent value="docs" className="h-full m-0">
|
||||
<DocumentationView />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="sass" className="h-full m-0">
|
||||
<SassStylesShowcase />
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
|
||||
|
||||
@@ -46,6 +46,10 @@ export function DocumentationView() {
|
||||
<FileCode size={18} />
|
||||
Agents Files
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="sass" className="gap-2">
|
||||
<PaintBrush size={18} />
|
||||
Sass Styles Guide
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
|
||||
@@ -728,6 +732,387 @@ export function DocumentationView() {
|
||||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="sass" className="m-0 space-y-6">
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-16 h-16 rounded-xl bg-gradient-to-br from-primary to-accent flex items-center justify-center">
|
||||
<PaintBrush size={32} weight="duotone" className="text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold">Sass Styles Guide</h1>
|
||||
<p className="text-lg text-muted-foreground">
|
||||
Custom Material UI components with Sass
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="space-y-4">
|
||||
<h2 className="text-2xl font-semibold">Overview</h2>
|
||||
<p className="text-foreground/90 leading-relaxed">
|
||||
CodeForge includes a comprehensive Sass-based styling system for non-standard Material UI components.
|
||||
This system provides pre-built components, utilities, mixins, and animations that extend beyond the
|
||||
standard Material UI component library.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>File Structure</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<div className="space-y-2">
|
||||
<code className="text-sm font-mono text-accent">src/styles/_variables.scss</code>
|
||||
<p className="text-sm text-muted-foreground ml-4">
|
||||
Color palettes, spacing scales, typography, transitions, and other design tokens
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<code className="text-sm font-mono text-accent">src/styles/_utilities.scss</code>
|
||||
<p className="text-sm text-muted-foreground ml-4">
|
||||
Mixins and functions for responsive design, colors, typography, and layout helpers
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<code className="text-sm font-mono text-accent">src/styles/_animations.scss</code>
|
||||
<p className="text-sm text-muted-foreground ml-4">
|
||||
Keyframe animations and animation utility classes for transitions and effects
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<code className="text-sm font-mono text-accent">src/styles/material-ui-custom.scss</code>
|
||||
<p className="text-sm text-muted-foreground ml-4">
|
||||
Custom Material UI component styles with variants and states
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<code className="text-sm font-mono text-accent">src/styles/main.scss</code>
|
||||
<p className="text-sm text-muted-foreground ml-4">
|
||||
Main entry point that imports all Sass modules and provides layout components
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Available Components</CardTitle>
|
||||
<CardDescription>Custom Material UI components built with Sass</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<SassComponentItem
|
||||
name="Buttons"
|
||||
classes={['mui-custom-button--primary', 'mui-custom-button--secondary', 'mui-custom-button--accent', 'mui-custom-button--outline', 'mui-custom-button--ghost']}
|
||||
description="Custom styled buttons with hover effects and variants"
|
||||
/>
|
||||
<SassComponentItem
|
||||
name="Cards"
|
||||
classes={['mui-custom-card', 'mui-custom-card--gradient', 'mui-custom-card--glass']}
|
||||
description="Elevated cards with gradient and glassmorphism variants"
|
||||
/>
|
||||
<SassComponentItem
|
||||
name="Inputs"
|
||||
classes={['mui-custom-input', 'mui-custom-input--error', 'mui-custom-input--success']}
|
||||
description="Form inputs with focus states and validation styling"
|
||||
/>
|
||||
<SassComponentItem
|
||||
name="Chips"
|
||||
classes={['mui-custom-chip--primary', 'mui-custom-chip--success', 'mui-custom-chip--error', 'mui-custom-chip--warning']}
|
||||
description="Status chips and tags with color variants"
|
||||
/>
|
||||
<SassComponentItem
|
||||
name="Panels"
|
||||
classes={['mui-custom-panel', 'mui-custom-panel--with-header']}
|
||||
description="Content panels with headers and footers"
|
||||
/>
|
||||
<SassComponentItem
|
||||
name="Dialogs"
|
||||
classes={['mui-custom-dialog']}
|
||||
description="Modal dialogs with backdrop blur effects"
|
||||
/>
|
||||
<SassComponentItem
|
||||
name="Badges"
|
||||
classes={['custom-mui-badge', 'custom-mui-badge--dot']}
|
||||
description="Notification badges and indicators"
|
||||
/>
|
||||
<SassComponentItem
|
||||
name="Progress"
|
||||
classes={['mui-custom-progress', 'mui-custom-progress--indeterminate']}
|
||||
description="Loading progress bars with animations"
|
||||
/>
|
||||
<SassComponentItem
|
||||
name="Skeletons"
|
||||
classes={['mui-custom-skeleton--text', 'mui-custom-skeleton--circle', 'mui-custom-skeleton--rect']}
|
||||
description="Loading skeleton placeholders with shimmer effect"
|
||||
/>
|
||||
<SassComponentItem
|
||||
name="Accordions"
|
||||
classes={['mui-custom-accordion']}
|
||||
description="Collapsible content sections with animations"
|
||||
/>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Layout Components</CardTitle>
|
||||
<CardDescription>Sass-powered layout utilities</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<FeatureItem
|
||||
icon={<Code size={18} />}
|
||||
title="custom-mui-container"
|
||||
description="Max-width container with responsive padding"
|
||||
/>
|
||||
<FeatureItem
|
||||
icon={<Code size={18} />}
|
||||
title="custom-mui-grid"
|
||||
description="CSS Grid layouts with responsive columns (--cols-1 to --cols-12, --responsive)"
|
||||
/>
|
||||
<FeatureItem
|
||||
icon={<Code size={18} />}
|
||||
title="custom-mui-flex"
|
||||
description="Flexbox utilities (--row, --col, --wrap, --center, --between, --around)"
|
||||
/>
|
||||
<FeatureItem
|
||||
icon={<Code size={18} />}
|
||||
title="custom-mui-stack"
|
||||
description="Vertical/horizontal stacks with configurable gaps"
|
||||
/>
|
||||
<FeatureItem
|
||||
icon={<Code size={18} />}
|
||||
title="custom-mui-surface"
|
||||
description="Interactive surfaces with elevation and hover effects"
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Sass Utilities & Mixins</CardTitle>
|
||||
<CardDescription>Reusable functions for custom styling</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-semibold flex items-center gap-2">
|
||||
<Lightbulb size={18} weight="duotone" className="text-accent" />
|
||||
Responsive Design
|
||||
</h3>
|
||||
<div className="ml-6 space-y-2 text-sm">
|
||||
<p className="font-mono text-accent">@include respond-to($breakpoint)</p>
|
||||
<p className="text-muted-foreground">Generate media queries for xs, sm, md, lg, xl, 2xl breakpoints</p>
|
||||
<pre className="custom-mui-code-block text-xs mt-2">
|
||||
{`@include respond-to('lg') {
|
||||
padding: 2rem;
|
||||
}`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-semibold flex items-center gap-2">
|
||||
<Lightbulb size={18} weight="duotone" className="text-accent" />
|
||||
Elevation & Shadows
|
||||
</h3>
|
||||
<div className="ml-6 space-y-2 text-sm">
|
||||
<p className="font-mono text-accent">@include elevation($level)</p>
|
||||
<p className="text-muted-foreground">Apply box shadows with levels 1-4</p>
|
||||
<pre className="custom-mui-code-block text-xs mt-2">
|
||||
{`@include elevation(2);`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-semibold flex items-center gap-2">
|
||||
<Lightbulb size={18} weight="duotone" className="text-accent" />
|
||||
Glassmorphism
|
||||
</h3>
|
||||
<div className="ml-6 space-y-2 text-sm">
|
||||
<p className="font-mono text-accent">@include glassmorphism($blur, $opacity)</p>
|
||||
<p className="text-muted-foreground">Create frosted glass effects with backdrop blur</p>
|
||||
<pre className="custom-mui-code-block text-xs mt-2">
|
||||
{`@include glassmorphism(16px, 0.1);`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-semibold flex items-center gap-2">
|
||||
<Lightbulb size={18} weight="duotone" className="text-accent" />
|
||||
Color Functions
|
||||
</h3>
|
||||
<div className="ml-6 space-y-2 text-sm">
|
||||
<p className="font-mono text-accent">get-color($palette, $shade)</p>
|
||||
<p className="text-muted-foreground">Access colors from predefined palettes (primary, secondary, accent, success, error, warning)</p>
|
||||
<pre className="custom-mui-code-block text-xs mt-2">
|
||||
{`color: get-color('primary', 500);`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-semibold flex items-center gap-2">
|
||||
<Lightbulb size={18} weight="duotone" className="text-accent" />
|
||||
Text Truncation
|
||||
</h3>
|
||||
<div className="ml-6 space-y-2 text-sm">
|
||||
<p className="font-mono text-accent">@include truncate($lines)</p>
|
||||
<p className="text-muted-foreground">Truncate text with ellipsis after specified lines</p>
|
||||
<pre className="custom-mui-code-block text-xs mt-2">
|
||||
{`@include truncate(2);`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-semibold flex items-center gap-2">
|
||||
<Lightbulb size={18} weight="duotone" className="text-accent" />
|
||||
Custom Scrollbars
|
||||
</h3>
|
||||
<div className="ml-6 space-y-2 text-sm">
|
||||
<p className="font-mono text-accent">@include show-scrollbar($track, $thumb)</p>
|
||||
<p className="text-muted-foreground">Style webkit scrollbars with custom colors</p>
|
||||
<pre className="custom-mui-code-block text-xs mt-2">
|
||||
{`@include show-scrollbar(rgba(0,0,0,0.1), rgba(0,0,0,0.3));`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Animation Classes</CardTitle>
|
||||
<CardDescription>Pre-built animation utilities</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid gap-3 md:grid-cols-2 lg:grid-cols-3">
|
||||
<AnimationItem name="animate-fade-in" description="Fade in from opacity 0" />
|
||||
<AnimationItem name="animate-slide-in-up" description="Slide in from bottom" />
|
||||
<AnimationItem name="animate-slide-in-down" description="Slide in from top" />
|
||||
<AnimationItem name="animate-scale-in" description="Scale in from 95%" />
|
||||
<AnimationItem name="animate-pulse" description="Pulsing opacity effect" />
|
||||
<AnimationItem name="animate-bounce" description="Bouncing effect" />
|
||||
<AnimationItem name="animate-spin" description="Continuous rotation" />
|
||||
<AnimationItem name="animate-shimmer" description="Shimmer effect for loading" />
|
||||
<AnimationItem name="animate-float" description="Floating up and down" />
|
||||
<AnimationItem name="animate-glow" description="Glowing shadow effect" />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-accent/5 border-accent/20">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Rocket size={20} weight="duotone" />
|
||||
Quick Start Example
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-semibold">Using Custom Components</h3>
|
||||
<pre className="custom-mui-code-block">
|
||||
{`import './styles/main.scss'
|
||||
|
||||
function MyComponent() {
|
||||
return (
|
||||
<div className="custom-mui-container">
|
||||
<div className="custom-mui-grid custom-mui-grid--cols-3">
|
||||
<div className="mui-custom-card">
|
||||
<h3>Card Title</h3>
|
||||
<p>Card content</p>
|
||||
<button className="mui-custom-button mui-custom-button--primary">
|
||||
Click Me
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}`}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-semibold">Creating Custom Styles with Mixins</h3>
|
||||
<pre className="custom-mui-code-block">
|
||||
{`@use './styles/utilities' as *;
|
||||
@use './styles/variables' as *;
|
||||
|
||||
.my-custom-component {
|
||||
@include elevation(2);
|
||||
@include responsive-padding(spacing('6'));
|
||||
background: get-color('primary', 500);
|
||||
|
||||
@include respond-to('md') {
|
||||
@include elevation(3);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@include glassmorphism(12px, 0.15);
|
||||
}
|
||||
}`}
|
||||
</pre>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-muted/50">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Target size={20} weight="duotone" />
|
||||
Best Practices
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle size={16} className="text-accent mt-1 flex-shrink-0" weight="fill" />
|
||||
<span>Import main.scss in your index.css to access all Sass components and utilities</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle size={16} className="text-accent mt-1 flex-shrink-0" weight="fill" />
|
||||
<span>Use @use instead of @import for better module encapsulation</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle size={16} className="text-accent mt-1 flex-shrink-0" weight="fill" />
|
||||
<span>Leverage mixins for consistent spacing, elevation, and responsive design</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle size={16} className="text-accent mt-1 flex-shrink-0" weight="fill" />
|
||||
<span>Extend existing component classes rather than creating from scratch</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle size={16} className="text-accent mt-1 flex-shrink-0" weight="fill" />
|
||||
<span>Use animation classes sparingly and respect prefers-reduced-motion</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle size={16} className="text-accent mt-1 flex-shrink-0" weight="fill" />
|
||||
<span>Customize variables in _variables.scss to match your design system</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</TabsContent>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</Tabs>
|
||||
@@ -735,6 +1120,29 @@ export function DocumentationView() {
|
||||
)
|
||||
}
|
||||
|
||||
function SassComponentItem({ name, classes, description }: { name: string; classes: string[]; description: string }) {
|
||||
return (
|
||||
<div className="space-y-2 p-4 border rounded-lg bg-card">
|
||||
<h4 className="font-semibold">{name}</h4>
|
||||
<p className="text-sm text-muted-foreground">{description}</p>
|
||||
<div className="space-y-1">
|
||||
{classes.map((cls, idx) => (
|
||||
<code key={idx} className="text-xs font-mono text-accent block">{cls}</code>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function AnimationItem({ name, description }: { name: string; description: string }) {
|
||||
return (
|
||||
<div className="space-y-1 p-3 border rounded-lg bg-card">
|
||||
<code className="text-xs font-mono text-accent">{name}</code>
|
||||
<p className="text-xs text-muted-foreground">{description}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function FeatureItem({ icon, title, description }: { icon: React.ReactNode; title: string; description: string }) {
|
||||
return (
|
||||
<div className="flex gap-3">
|
||||
|
||||
320
src/components/SassStylesShowcase.tsx
Normal file
320
src/components/SassStylesShowcase.tsx
Normal file
@@ -0,0 +1,320 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Code, Palette, Sparkle, CheckCircle } from '@phosphor-icons/react'
|
||||
|
||||
export function SassStylesShowcase() {
|
||||
return (
|
||||
<div className="h-full p-6 space-y-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold mb-2">Custom Material UI Sass Styles</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Non-standard Material UI CSS components built with Sass
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Tabs defaultValue="buttons" className="flex-1">
|
||||
<TabsList>
|
||||
<TabsTrigger value="buttons">Buttons</TabsTrigger>
|
||||
<TabsTrigger value="inputs">Inputs</TabsTrigger>
|
||||
<TabsTrigger value="cards">Cards</TabsTrigger>
|
||||
<TabsTrigger value="chips">Chips</TabsTrigger>
|
||||
<TabsTrigger value="layout">Layout</TabsTrigger>
|
||||
<TabsTrigger value="animations">Animations</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="buttons" className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Custom Button Styles</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="space-y-3">
|
||||
<div className="flex gap-3 flex-wrap">
|
||||
<button className="mui-custom-button mui-custom-button--primary">
|
||||
Primary Button
|
||||
</button>
|
||||
<button className="mui-custom-button mui-custom-button--secondary">
|
||||
Secondary Button
|
||||
</button>
|
||||
<button className="mui-custom-button mui-custom-button--accent">
|
||||
Accent Button
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3 flex-wrap">
|
||||
<button className="mui-custom-button mui-custom-button--outline">
|
||||
Outline Button
|
||||
</button>
|
||||
<button className="mui-custom-button mui-custom-button--ghost">
|
||||
Ghost Button
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<pre className="custom-mui-code-block">
|
||||
{`<button className="mui-custom-button mui-custom-button--primary">
|
||||
Primary Button
|
||||
</button>
|
||||
|
||||
<button className="mui-custom-button mui-custom-button--accent">
|
||||
Accent Button
|
||||
</button>`}
|
||||
</pre>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="inputs" className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Custom Input Styles</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="space-y-3">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Default input"
|
||||
className="mui-custom-input w-full"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Error state"
|
||||
className="mui-custom-input mui-custom-input--error w-full"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Success state"
|
||||
className="mui-custom-input mui-custom-input--success w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<pre className="custom-mui-code-block">
|
||||
{`<input
|
||||
className="mui-custom-input"
|
||||
placeholder="Your input"
|
||||
/>
|
||||
|
||||
<input
|
||||
className="mui-custom-input mui-custom-input--error"
|
||||
placeholder="Error state"
|
||||
/>`}
|
||||
</pre>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="cards" className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Custom Card Styles</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div className="mui-custom-card p-6">
|
||||
<h3 className="font-bold mb-2">Standard Card</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Basic card with elevation and hover effect
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mui-custom-card mui-custom-card--gradient p-6">
|
||||
<h3 className="font-bold mb-2">Gradient Card</h3>
|
||||
<p className="text-sm opacity-90">
|
||||
Card with gradient background
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mui-custom-card mui-custom-card--glass p-6">
|
||||
<h3 className="font-bold mb-2">Glass Card</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Glassmorphism effect card
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<pre className="custom-mui-code-block">
|
||||
{`<div className="mui-custom-card">
|
||||
Standard Card
|
||||
</div>
|
||||
|
||||
<div className="mui-custom-card mui-custom-card--gradient">
|
||||
Gradient Card
|
||||
</div>
|
||||
|
||||
<div className="mui-custom-card mui-custom-card--glass">
|
||||
Glass Card
|
||||
</div>`}
|
||||
</pre>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="chips" className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Custom Chip/Badge Styles</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
<span className="mui-custom-chip mui-custom-chip--primary">
|
||||
Primary
|
||||
</span>
|
||||
<span className="mui-custom-chip mui-custom-chip--secondary">
|
||||
Secondary
|
||||
</span>
|
||||
<span className="mui-custom-chip mui-custom-chip--accent">
|
||||
Accent
|
||||
</span>
|
||||
<span className="mui-custom-chip mui-custom-chip--success">
|
||||
<CheckCircle size={14} weight="fill" />
|
||||
Success
|
||||
</span>
|
||||
<span className="mui-custom-chip mui-custom-chip--error">
|
||||
Error
|
||||
</span>
|
||||
<span className="mui-custom-chip mui-custom-chip--warning">
|
||||
Warning
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<pre className="custom-mui-code-block">
|
||||
{`<span className="mui-custom-chip mui-custom-chip--primary">
|
||||
Primary
|
||||
</span>
|
||||
|
||||
<span className="mui-custom-chip mui-custom-chip--success">
|
||||
<CheckCircle size={14} />
|
||||
Success
|
||||
</span>`}
|
||||
</pre>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Custom Tags</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
<span className="custom-mui-tag">Default</span>
|
||||
<span className="custom-mui-tag custom-mui-tag--sm">Small</span>
|
||||
<span className="custom-mui-tag custom-mui-tag--lg">Large</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="layout" className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Custom Layout Components</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-6">
|
||||
<div>
|
||||
<h3 className="font-semibold mb-3">Custom Stack</h3>
|
||||
<div className="custom-mui-stack custom-mui-stack--gap-3">
|
||||
<div className="p-4 bg-card border rounded">Item 1</div>
|
||||
<div className="p-4 bg-card border rounded">Item 2</div>
|
||||
<div className="p-4 bg-card border rounded">Item 3</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="font-semibold mb-3">Custom Grid (Responsive)</h3>
|
||||
<div className="custom-mui-grid custom-mui-grid--responsive">
|
||||
<div className="p-4 bg-card border rounded">Grid 1</div>
|
||||
<div className="p-4 bg-card border rounded">Grid 2</div>
|
||||
<div className="p-4 bg-card border rounded">Grid 3</div>
|
||||
<div className="p-4 bg-card border rounded">Grid 4</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="font-semibold mb-3">Custom Surface</h3>
|
||||
<div className="custom-mui-surface custom-mui-surface--interactive">
|
||||
<p>Interactive surface with hover effects</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<pre className="custom-mui-code-block">
|
||||
{`<div className="custom-mui-stack custom-mui-stack--gap-3">
|
||||
<div>Item 1</div>
|
||||
<div>Item 2</div>
|
||||
</div>
|
||||
|
||||
<div className="custom-mui-grid custom-mui-grid--responsive">
|
||||
<div>Grid Item</div>
|
||||
</div>`}
|
||||
</pre>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="animations" className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Animation Classes</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||||
<div className="p-4 bg-card border rounded animate-fade-in">
|
||||
Fade In
|
||||
</div>
|
||||
<div className="p-4 bg-card border rounded animate-slide-in-up">
|
||||
Slide Up
|
||||
</div>
|
||||
<div className="p-4 bg-card border rounded animate-scale-in">
|
||||
Scale In
|
||||
</div>
|
||||
<div className="p-4 bg-card border rounded animate-pulse">
|
||||
Pulse
|
||||
</div>
|
||||
<div className="p-4 bg-card border rounded animate-bounce">
|
||||
Bounce
|
||||
</div>
|
||||
<div className="p-4 bg-card border rounded animate-float">
|
||||
Float
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<pre className="custom-mui-code-block">
|
||||
{`<div className="animate-fade-in">Fade In</div>
|
||||
<div className="animate-slide-in-up">Slide Up</div>
|
||||
<div className="animate-pulse">Pulse</div>
|
||||
<div className="animate-bounce">Bounce</div>`}
|
||||
</pre>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Skeleton Loading</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="space-y-3">
|
||||
<div className="mui-custom-skeleton mui-custom-skeleton--text" />
|
||||
<div className="mui-custom-skeleton mui-custom-skeleton--text" />
|
||||
<div className="mui-custom-skeleton mui-custom-skeleton--rect" />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
@import 'tailwindcss';
|
||||
@import "tw-animate-css";
|
||||
@import './styles/main.scss';
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
|
||||
364
src/styles/_animations.scss
Normal file
364
src/styles/_animations.scss
Normal file
@@ -0,0 +1,364 @@
|
||||
@use './variables' as *;
|
||||
|
||||
@keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-out {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-in-up {
|
||||
from {
|
||||
transform: translateY(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-in-down {
|
||||
from {
|
||||
transform: translateY(-100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-in-left {
|
||||
from {
|
||||
transform: translateX(-100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-in-right {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scale-in {
|
||||
from {
|
||||
transform: scale(0.95);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scale-out {
|
||||
from {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
transform: scale(0.95);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%, 100% {
|
||||
transform: translateY(0);
|
||||
animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-25%);
|
||||
animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ping {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
75%, 100% {
|
||||
transform: scale(2);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
background-position: -1000px 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 1000px 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0%, 100% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
10%, 30%, 50%, 70%, 90% {
|
||||
transform: translateX(-10px);
|
||||
}
|
||||
20%, 40%, 60%, 80% {
|
||||
transform: translateX(10px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes swing {
|
||||
0%, 100% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
20% {
|
||||
transform: rotate(15deg);
|
||||
}
|
||||
40% {
|
||||
transform: rotate(-10deg);
|
||||
}
|
||||
60% {
|
||||
transform: rotate(5deg);
|
||||
}
|
||||
80% {
|
||||
transform: rotate(-5deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate-in {
|
||||
from {
|
||||
transform: rotate(-180deg) scale(0.8);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: rotate(0deg) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes flip {
|
||||
from {
|
||||
transform: perspective(400px) rotateY(90deg);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: perspective(400px) rotateY(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes glow {
|
||||
0%, 100% {
|
||||
box-shadow: 0 0 5px rgba($accent-color, 0.2);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 20px rgba($accent-color, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes gradient-shift {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes wave {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
10% {
|
||||
transform: rotate(14deg);
|
||||
}
|
||||
20% {
|
||||
transform: rotate(-8deg);
|
||||
}
|
||||
30% {
|
||||
transform: rotate(14deg);
|
||||
}
|
||||
40% {
|
||||
transform: rotate(-4deg);
|
||||
}
|
||||
50% {
|
||||
transform: rotate(10deg);
|
||||
}
|
||||
60% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes typing {
|
||||
from {
|
||||
width: 0;
|
||||
}
|
||||
to {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-fade-in {
|
||||
animation: fade-in $transition-base forwards;
|
||||
}
|
||||
|
||||
.animate-fade-out {
|
||||
animation: fade-out $transition-base forwards;
|
||||
}
|
||||
|
||||
.animate-slide-in-up {
|
||||
animation: slide-in-up $transition-base $easing-ease-out;
|
||||
}
|
||||
|
||||
.animate-slide-in-down {
|
||||
animation: slide-in-down $transition-base $easing-ease-out;
|
||||
}
|
||||
|
||||
.animate-slide-in-left {
|
||||
animation: slide-in-left $transition-base $easing-ease-out;
|
||||
}
|
||||
|
||||
.animate-slide-in-right {
|
||||
animation: slide-in-right $transition-base $easing-ease-out;
|
||||
}
|
||||
|
||||
.animate-scale-in {
|
||||
animation: scale-in $transition-base $easing-ease-out;
|
||||
}
|
||||
|
||||
.animate-scale-out {
|
||||
animation: scale-out $transition-base $easing-ease-out;
|
||||
}
|
||||
|
||||
.animate-bounce {
|
||||
animation: bounce 1s infinite;
|
||||
}
|
||||
|
||||
.animate-pulse {
|
||||
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
.animate-ping {
|
||||
animation: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
|
||||
}
|
||||
|
||||
.animate-spin {
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.animate-shimmer {
|
||||
animation: shimmer 2s infinite;
|
||||
}
|
||||
|
||||
.animate-shake {
|
||||
animation: shake 0.5s;
|
||||
}
|
||||
|
||||
.animate-swing {
|
||||
animation: swing 1s ease-in-out;
|
||||
}
|
||||
|
||||
.animate-rotate-in {
|
||||
animation: rotate-in $transition-base $easing-ease-out;
|
||||
}
|
||||
|
||||
.animate-flip {
|
||||
animation: flip $transition-base $easing-ease-out;
|
||||
}
|
||||
|
||||
.animate-glow {
|
||||
animation: glow 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animate-gradient-shift {
|
||||
animation: gradient-shift 3s ease infinite;
|
||||
background-size: 200% 200%;
|
||||
}
|
||||
|
||||
.animate-float {
|
||||
animation: float 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animate-wave {
|
||||
animation: wave 2s ease-in-out;
|
||||
}
|
||||
|
||||
.animate-typing {
|
||||
animation: typing 3.5s steps(40, end);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
border-right: 3px solid;
|
||||
animation: typing 3.5s steps(40, end), blink 0.75s step-end infinite;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
333
src/styles/_utilities.scss
Normal file
333
src/styles/_utilities.scss
Normal file
@@ -0,0 +1,333 @@
|
||||
@use 'sass:color';
|
||||
@use 'sass:map';
|
||||
|
||||
$breakpoints: (
|
||||
'xs': 480px,
|
||||
'sm': 640px,
|
||||
'md': 768px,
|
||||
'lg': 1024px,
|
||||
'xl': 1280px,
|
||||
'2xl': 1536px,
|
||||
);
|
||||
|
||||
@function breakpoint($size) {
|
||||
@return map.get($breakpoints, $size);
|
||||
}
|
||||
|
||||
@mixin respond-to($breakpoint) {
|
||||
@if map.has-key($breakpoints, $breakpoint) {
|
||||
@media (min-width: map.get($breakpoints, $breakpoint)) {
|
||||
@content;
|
||||
}
|
||||
} @else {
|
||||
@warn "Unknown breakpoint: #{$breakpoint}";
|
||||
}
|
||||
}
|
||||
|
||||
@mixin respond-below($breakpoint) {
|
||||
@if map.has-key($breakpoints, $breakpoint) {
|
||||
@media (max-width: map.get($breakpoints, $breakpoint) - 1px) {
|
||||
@content;
|
||||
}
|
||||
} @else {
|
||||
@warn "Unknown breakpoint: #{$breakpoint}";
|
||||
}
|
||||
}
|
||||
|
||||
@mixin respond-between($min, $max) {
|
||||
@if map.has-key($breakpoints, $min) and map.has-key($breakpoints, $max) {
|
||||
@media (min-width: map.get($breakpoints, $min)) and (max-width: map.get($breakpoints, $max) - 1px) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$spacing-scale: (
|
||||
'0': 0,
|
||||
'1': 0.25rem,
|
||||
'2': 0.5rem,
|
||||
'3': 0.75rem,
|
||||
'4': 1rem,
|
||||
'5': 1.25rem,
|
||||
'6': 1.5rem,
|
||||
'8': 2rem,
|
||||
'10': 2.5rem,
|
||||
'12': 3rem,
|
||||
'16': 4rem,
|
||||
'20': 5rem,
|
||||
'24': 6rem,
|
||||
);
|
||||
|
||||
@function spacing($size) {
|
||||
@return map.get($spacing-scale, $size);
|
||||
}
|
||||
|
||||
$color-palette: (
|
||||
'primary': (
|
||||
50: #eef2ff,
|
||||
100: #e0e7ff,
|
||||
200: #c7d2fe,
|
||||
300: #a5b4fc,
|
||||
400: #818cf8,
|
||||
500: #6366f1,
|
||||
600: #4f46e5,
|
||||
700: #4338ca,
|
||||
800: #3730a3,
|
||||
900: #312e81,
|
||||
),
|
||||
'secondary': (
|
||||
50: #faf5ff,
|
||||
100: #f3e8ff,
|
||||
200: #e9d5ff,
|
||||
300: #d8b4fe,
|
||||
400: #c084fc,
|
||||
500: #a855f7,
|
||||
600: #9333ea,
|
||||
700: #7e22ce,
|
||||
800: #6b21a8,
|
||||
900: #581c87,
|
||||
),
|
||||
'accent': (
|
||||
50: #ecfeff,
|
||||
100: #cffafe,
|
||||
200: #a5f3fc,
|
||||
300: #67e8f9,
|
||||
400: #22d3ee,
|
||||
500: #06b6d4,
|
||||
600: #0891b2,
|
||||
700: #0e7490,
|
||||
800: #155e75,
|
||||
900: #164e63,
|
||||
),
|
||||
'success': (
|
||||
50: #f0fdf4,
|
||||
100: #dcfce7,
|
||||
200: #bbf7d0,
|
||||
300: #86efac,
|
||||
400: #4ade80,
|
||||
500: #22c55e,
|
||||
600: #16a34a,
|
||||
700: #15803d,
|
||||
800: #166534,
|
||||
900: #14532d,
|
||||
),
|
||||
'error': (
|
||||
50: #fef2f2,
|
||||
100: #fee2e2,
|
||||
200: #fecaca,
|
||||
300: #fca5a5,
|
||||
400: #f87171,
|
||||
500: #ef4444,
|
||||
600: #dc2626,
|
||||
700: #b91c1c,
|
||||
800: #991b1b,
|
||||
900: #7f1d1d,
|
||||
),
|
||||
'warning': (
|
||||
50: #fffbeb,
|
||||
100: #fef3c7,
|
||||
200: #fde68a,
|
||||
300: #fcd34d,
|
||||
400: #fbbf24,
|
||||
500: #f59e0b,
|
||||
600: #d97706,
|
||||
700: #b45309,
|
||||
800: #92400e,
|
||||
900: #78350f,
|
||||
),
|
||||
'gray': (
|
||||
50: #f9fafb,
|
||||
100: #f3f4f6,
|
||||
200: #e5e7eb,
|
||||
300: #d1d5db,
|
||||
400: #9ca3af,
|
||||
500: #6b7280,
|
||||
600: #4b5563,
|
||||
700: #374151,
|
||||
800: #1f2937,
|
||||
900: #111827,
|
||||
),
|
||||
);
|
||||
|
||||
@function get-color($palette, $shade: 500) {
|
||||
@if map.has-key($color-palette, $palette) {
|
||||
$palette-map: map.get($color-palette, $palette);
|
||||
@return map.get($palette-map, $shade);
|
||||
}
|
||||
@warn "Unknown color palette: #{$palette}";
|
||||
@return null;
|
||||
}
|
||||
|
||||
@mixin theme-colors($theme-name) {
|
||||
&[data-theme='#{$theme-name}'] {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin transition($properties: all, $duration: 0.3s, $timing: ease) {
|
||||
transition: $properties $duration $timing;
|
||||
}
|
||||
|
||||
@mixin truncate($lines: 1) {
|
||||
@if $lines == 1 {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
} @else {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: $lines;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin center($direction: 'both') {
|
||||
display: flex;
|
||||
|
||||
@if $direction == 'both' {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
} @else if $direction == 'horizontal' {
|
||||
justify-content: center;
|
||||
} @else if $direction == 'vertical' {
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin aspect-ratio($width, $height) {
|
||||
aspect-ratio: #{$width} / #{$height};
|
||||
|
||||
@supports not (aspect-ratio: 1 / 1) {
|
||||
&::before {
|
||||
content: '';
|
||||
padding-top: percentage($height / $width);
|
||||
float: left;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin focus-ring($color: #06b6d4, $width: 3px, $offset: 2px) {
|
||||
&:focus {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 $width rgba($color, 0.3);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: $width solid rgba($color, 0.5);
|
||||
outline-offset: $offset;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin hide-scrollbar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin show-scrollbar($track-color: rgba(255, 255, 255, 0.1), $thumb-color: rgba(255, 255, 255, 0.3)) {
|
||||
&::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: $track-color;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: $thumb-color;
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background: color.adjust($thumb-color, $lightness: 10%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin visually-hidden {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
@mixin reset-button {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin reset-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
$font-sizes: (
|
||||
'xs': 0.75rem,
|
||||
'sm': 0.875rem,
|
||||
'base': 1rem,
|
||||
'lg': 1.125rem,
|
||||
'xl': 1.25rem,
|
||||
'2xl': 1.5rem,
|
||||
'3xl': 1.875rem,
|
||||
'4xl': 2.25rem,
|
||||
'5xl': 3rem,
|
||||
);
|
||||
|
||||
@function font-size($size) {
|
||||
@return map.get($font-sizes, $size);
|
||||
}
|
||||
|
||||
$font-weights: (
|
||||
'thin': 100,
|
||||
'light': 300,
|
||||
'normal': 400,
|
||||
'medium': 500,
|
||||
'semibold': 600,
|
||||
'bold': 700,
|
||||
'extrabold': 800,
|
||||
'black': 900,
|
||||
);
|
||||
|
||||
@function font-weight($weight) {
|
||||
@return map.get($font-weights, $weight);
|
||||
}
|
||||
|
||||
$z-index-layers: (
|
||||
'base': 0,
|
||||
'dropdown': 1000,
|
||||
'sticky': 1020,
|
||||
'fixed': 1030,
|
||||
'modal-backdrop': 1040,
|
||||
'modal': 1050,
|
||||
'popover': 1060,
|
||||
'tooltip': 1070,
|
||||
);
|
||||
|
||||
@function z-index($layer) {
|
||||
@return map.get($z-index-layers, $layer);
|
||||
}
|
||||
72
src/styles/_variables.scss
Normal file
72
src/styles/_variables.scss
Normal file
@@ -0,0 +1,72 @@
|
||||
$primary-color: #6366f1;
|
||||
$primary-light: #818cf8;
|
||||
$primary-dark: #4338ca;
|
||||
|
||||
$secondary-color: #8b5cf6;
|
||||
$secondary-light: #a78bfa;
|
||||
$secondary-dark: #7c3aed;
|
||||
|
||||
$accent-color: #06b6d4;
|
||||
$accent-light: #22d3ee;
|
||||
$accent-dark: #0891b2;
|
||||
|
||||
$success-color: #10b981;
|
||||
$error-color: #ef4444;
|
||||
$warning-color: #f59e0b;
|
||||
$info-color: #3b82f6;
|
||||
|
||||
$background-dark: #1a1d29;
|
||||
$background-card: #23273a;
|
||||
$background-elevated: #2d3348;
|
||||
$background-hover: rgba(255, 255, 255, 0.05);
|
||||
|
||||
$text-primary: #e8eaed;
|
||||
$text-secondary: #a8abb5;
|
||||
$text-disabled: #6b6e7b;
|
||||
$text-inverse: #1a1d29;
|
||||
|
||||
$border-color: rgba(255, 255, 255, 0.1);
|
||||
$border-color-strong: rgba(255, 255, 255, 0.2);
|
||||
$border-color-weak: rgba(255, 255, 255, 0.05);
|
||||
|
||||
$shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
$shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
$shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
$shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
$shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||
|
||||
$radius-sm: 0.25rem;
|
||||
$radius-md: 0.5rem;
|
||||
$radius-lg: 0.75rem;
|
||||
$radius-xl: 1rem;
|
||||
$radius-2xl: 1.5rem;
|
||||
$radius-full: 9999px;
|
||||
|
||||
$spacing-xs: 0.25rem;
|
||||
$spacing-sm: 0.5rem;
|
||||
$spacing-md: 1rem;
|
||||
$spacing-lg: 1.5rem;
|
||||
$spacing-xl: 2rem;
|
||||
$spacing-2xl: 3rem;
|
||||
|
||||
$font-family-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
$font-family-display: 'Space Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
$font-family-mono: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
|
||||
|
||||
$transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
$transition-base: 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
$transition-slow: 500ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
$easing-linear: linear;
|
||||
$easing-ease: ease;
|
||||
$easing-ease-in: ease-in;
|
||||
$easing-ease-out: ease-out;
|
||||
$easing-ease-in-out: ease-in-out;
|
||||
$easing-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
$easing-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||
|
||||
$grid-columns: 12;
|
||||
$grid-gutter: 1rem;
|
||||
|
||||
$container-max-width: 1280px;
|
||||
$container-padding: 1rem;
|
||||
573
src/styles/main.scss
Normal file
573
src/styles/main.scss
Normal file
@@ -0,0 +1,573 @@
|
||||
@use './variables' as *;
|
||||
@use './utilities' as *;
|
||||
@use './animations';
|
||||
@use './material-ui-custom';
|
||||
|
||||
.mui-enhanced {
|
||||
font-family: $font-family-sans;
|
||||
color: $text-primary;
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
code, pre {
|
||||
font-family: $font-family-mono;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: $font-family-display;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-container {
|
||||
max-width: $container-max-width;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: $container-padding;
|
||||
padding-right: $container-padding;
|
||||
|
||||
@include respond-to('lg') {
|
||||
padding-left: calc($container-padding * 2);
|
||||
padding-right: calc($container-padding * 2);
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-grid {
|
||||
display: grid;
|
||||
gap: $grid-gutter;
|
||||
|
||||
&--cols-1 {
|
||||
grid-template-columns: repeat(1, 1fr);
|
||||
}
|
||||
|
||||
&--cols-2 {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
&--cols-3 {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
&--cols-4 {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
|
||||
&--cols-6 {
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
}
|
||||
|
||||
&--cols-12 {
|
||||
grid-template-columns: repeat(12, 1fr);
|
||||
}
|
||||
|
||||
&--responsive {
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-flex {
|
||||
display: flex;
|
||||
|
||||
&--row {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
&--col {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&--wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&--center {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&--between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&--around {
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
&--evenly {
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
&--start {
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
&--end {
|
||||
justify-content: flex-end;
|
||||
align-items: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-stack {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: spacing('4');
|
||||
|
||||
&--horizontal {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
&--gap-1 {
|
||||
gap: spacing('1');
|
||||
}
|
||||
|
||||
&--gap-2 {
|
||||
gap: spacing('2');
|
||||
}
|
||||
|
||||
&--gap-3 {
|
||||
gap: spacing('3');
|
||||
}
|
||||
|
||||
&--gap-4 {
|
||||
gap: spacing('4');
|
||||
}
|
||||
|
||||
&--gap-6 {
|
||||
gap: spacing('6');
|
||||
}
|
||||
|
||||
&--gap-8 {
|
||||
gap: spacing('8');
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-surface {
|
||||
background: $background-card;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: $radius-lg;
|
||||
padding: spacing('6');
|
||||
|
||||
&--elevated {
|
||||
box-shadow: $shadow-lg;
|
||||
background: $background-elevated;
|
||||
}
|
||||
|
||||
&--interactive {
|
||||
cursor: pointer;
|
||||
transition: all $transition-base;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: $shadow-xl;
|
||||
border-color: $border-color-strong;
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: $shadow-md;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
backdrop-filter: blur(4px);
|
||||
z-index: z-index('modal-backdrop');
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
animation: fade-in $transition-fast;
|
||||
}
|
||||
|
||||
.custom-mui-drawer {
|
||||
position: fixed;
|
||||
background: $background-card;
|
||||
z-index: z-index('modal');
|
||||
box-shadow: $shadow-2xl;
|
||||
overflow-y: auto;
|
||||
|
||||
&--left {
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 320px;
|
||||
animation: slide-in-left $transition-base;
|
||||
}
|
||||
|
||||
&--right {
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 320px;
|
||||
animation: slide-in-right $transition-base;
|
||||
}
|
||||
|
||||
&--top {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: auto;
|
||||
animation: slide-in-down $transition-base;
|
||||
}
|
||||
|
||||
&--bottom {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: auto;
|
||||
max-height: 90vh;
|
||||
animation: slide-in-up $transition-base;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-navbar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: z-index('sticky');
|
||||
background: rgba($background-card, 0.9);
|
||||
backdrop-filter: blur(12px);
|
||||
border-bottom: 1px solid $border-color;
|
||||
padding: spacing('4') spacing('6');
|
||||
|
||||
@include respond-below('md') {
|
||||
padding: spacing('3') spacing('4');
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-sidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 280px;
|
||||
background: $background-card;
|
||||
border-right: 1px solid $border-color;
|
||||
overflow-y: auto;
|
||||
z-index: z-index('fixed');
|
||||
|
||||
@include respond-below('lg') {
|
||||
transform: translateX(-100%);
|
||||
transition: transform $transition-base;
|
||||
|
||||
&--open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-footer {
|
||||
background: $background-card;
|
||||
border-top: 1px solid $border-color;
|
||||
padding: spacing('8') spacing('6');
|
||||
margin-top: auto;
|
||||
|
||||
@include respond-below('md') {
|
||||
padding: spacing('6') spacing('4');
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-breadcrumbs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: spacing('2');
|
||||
flex-wrap: wrap;
|
||||
|
||||
&-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: $text-secondary;
|
||||
font-size: font-size('sm');
|
||||
|
||||
&--active {
|
||||
color: $text-primary;
|
||||
font-weight: font-weight('medium');
|
||||
}
|
||||
|
||||
&:not(:last-child)::after {
|
||||
content: '/';
|
||||
margin-left: spacing('2');
|
||||
color: $text-disabled;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
transition: color $transition-fast;
|
||||
|
||||
&:hover {
|
||||
color: $accent-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-stepper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&-step {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: spacing('2');
|
||||
flex: 1;
|
||||
position: relative;
|
||||
|
||||
&:not(:last-child)::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 50%;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: $border-color;
|
||||
}
|
||||
|
||||
&--completed::after {
|
||||
background: $success-color;
|
||||
}
|
||||
|
||||
&--active::after {
|
||||
background: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-icon {
|
||||
@include center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: $radius-full;
|
||||
background: $background-elevated;
|
||||
border: 2px solid $border-color;
|
||||
color: $text-secondary;
|
||||
font-size: font-size('sm');
|
||||
font-weight: font-weight('semibold');
|
||||
z-index: 1;
|
||||
|
||||
.custom-mui-stepper-step--completed & {
|
||||
background: $success-color;
|
||||
border-color: $success-color;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.custom-mui-stepper-step--active & {
|
||||
background: $primary-color;
|
||||
border-color: $primary-color;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&-label {
|
||||
font-size: font-size('sm');
|
||||
color: $text-secondary;
|
||||
text-align: center;
|
||||
|
||||
.custom-mui-stepper-step--active & {
|
||||
color: $text-primary;
|
||||
font-weight: font-weight('medium');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-timeline {
|
||||
position: relative;
|
||||
padding-left: spacing('6');
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 2px;
|
||||
background: $border-color;
|
||||
}
|
||||
|
||||
&-item {
|
||||
position: relative;
|
||||
padding-bottom: spacing('6');
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -29px;
|
||||
top: 4px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: $radius-full;
|
||||
background: $primary-color;
|
||||
border: 2px solid $background-dark;
|
||||
}
|
||||
|
||||
&--success::before {
|
||||
background: $success-color;
|
||||
}
|
||||
|
||||
&--error::before {
|
||||
background: $error-color;
|
||||
}
|
||||
|
||||
&--warning::before {
|
||||
background: $warning-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
|
||||
thead {
|
||||
background: $background-elevated;
|
||||
border-bottom: 2px solid $border-color-strong;
|
||||
}
|
||||
|
||||
th {
|
||||
padding: spacing('3') spacing('4');
|
||||
text-align: left;
|
||||
font-weight: font-weight('semibold');
|
||||
font-size: font-size('sm');
|
||||
color: $text-secondary;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: spacing('3') spacing('4');
|
||||
border-bottom: 1px solid $border-color;
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
transition: background $transition-fast;
|
||||
|
||||
&:hover {
|
||||
background: $background-hover;
|
||||
}
|
||||
}
|
||||
|
||||
&--striped tbody tr:nth-child(even) {
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
}
|
||||
|
||||
&--bordered {
|
||||
border: 1px solid $border-color;
|
||||
|
||||
td, th {
|
||||
border: 1px solid $border-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-list {
|
||||
@include reset-list;
|
||||
|
||||
&-item {
|
||||
padding: spacing('3') spacing('4');
|
||||
transition: background $transition-fast;
|
||||
border-radius: $radius-md;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: $background-hover;
|
||||
}
|
||||
|
||||
&--active {
|
||||
background: rgba($primary-color, 0.1);
|
||||
color: $primary-color;
|
||||
font-weight: font-weight('medium');
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
&--bordered &-item {
|
||||
border: 1px solid $border-color;
|
||||
margin-bottom: spacing('2');
|
||||
}
|
||||
|
||||
&--divided &-item {
|
||||
border-bottom: 1px solid $border-color;
|
||||
border-radius: 0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-code-block {
|
||||
background: $background-elevated;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: $radius-md;
|
||||
padding: spacing('4');
|
||||
overflow-x: auto;
|
||||
font-family: $font-family-mono;
|
||||
font-size: font-size('sm');
|
||||
|
||||
@include show-scrollbar;
|
||||
|
||||
pre {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
code {
|
||||
color: $text-primary;
|
||||
font-family: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-mui-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: spacing('1');
|
||||
padding: spacing('1') spacing('2');
|
||||
border-radius: $radius-md;
|
||||
font-size: font-size('xs');
|
||||
font-weight: font-weight('medium');
|
||||
background: rgba($primary-color, 0.15);
|
||||
color: $primary-color;
|
||||
|
||||
&--sm {
|
||||
padding: 2px spacing('1');
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
&--lg {
|
||||
padding: spacing('2') spacing('3');
|
||||
font-size: font-size('sm');
|
||||
}
|
||||
}
|
||||
|
||||
.utility-text {
|
||||
&-truncate {
|
||||
@include truncate(1);
|
||||
}
|
||||
|
||||
&-truncate-2 {
|
||||
@include truncate(2);
|
||||
}
|
||||
|
||||
&-truncate-3 {
|
||||
@include truncate(3);
|
||||
}
|
||||
}
|
||||
|
||||
.utility-visually-hidden {
|
||||
@include visually-hidden;
|
||||
}
|
||||
|
||||
.utility-focus-ring {
|
||||
@include focus-ring;
|
||||
}
|
||||
532
src/styles/material-ui-custom.scss
Normal file
532
src/styles/material-ui-custom.scss
Normal file
@@ -0,0 +1,532 @@
|
||||
@use 'sass:color';
|
||||
@use 'sass:map';
|
||||
|
||||
$primary-color: #6366f1;
|
||||
$secondary-color: #8b5cf6;
|
||||
$accent-color: #06b6d4;
|
||||
$background-dark: #1a1d29;
|
||||
$background-card: #23273a;
|
||||
$text-light: #e8eaed;
|
||||
|
||||
@mixin elevation($level) {
|
||||
@if $level == 1 {
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
} @else if $level == 2 {
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
||||
} @else if $level == 3 {
|
||||
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
|
||||
} @else if $level == 4 {
|
||||
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin responsive-padding($base-padding) {
|
||||
padding: $base-padding;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: $base-padding * 0.75;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
padding: $base-padding * 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin glassmorphism($blur: 10px, $opacity: 0.1) {
|
||||
background: rgba(255, 255, 255, $opacity);
|
||||
backdrop-filter: blur($blur);
|
||||
-webkit-backdrop-filter: blur($blur);
|
||||
}
|
||||
|
||||
@mixin gradient-background($start-color, $end-color, $angle: 135deg) {
|
||||
background: linear-gradient($angle, $start-color, $end-color);
|
||||
}
|
||||
|
||||
.mui-custom {
|
||||
&-card {
|
||||
@include elevation(2);
|
||||
border-radius: 12px;
|
||||
background-color: $background-card;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
@include elevation(3);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
&--gradient {
|
||||
@include gradient-background($primary-color, $secondary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
&--glass {
|
||||
@include glassmorphism(16px, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
&-button {
|
||||
@include responsive-padding(12px);
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
text-transform: none;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&--primary {
|
||||
background: $primary-color;
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background: color.adjust($primary-color, $lightness: 10%);
|
||||
box-shadow: 0 4px 12px rgba($primary-color, 0.4);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
&--secondary {
|
||||
background: $secondary-color;
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background: color.adjust($secondary-color, $lightness: 10%);
|
||||
box-shadow: 0 4px 12px rgba($secondary-color, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
&--accent {
|
||||
background: $accent-color;
|
||||
color: $background-dark;
|
||||
|
||||
&:hover {
|
||||
background: color.adjust($accent-color, $lightness: 10%);
|
||||
box-shadow: 0 4px 12px rgba($accent-color, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
&--outline {
|
||||
background: transparent;
|
||||
border: 2px solid $primary-color;
|
||||
color: $primary-color;
|
||||
|
||||
&:hover {
|
||||
background: rgba($primary-color, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
&--ghost {
|
||||
background: transparent;
|
||||
color: $text-light;
|
||||
|
||||
&:hover {
|
||||
background: rgba($text-light, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-input {
|
||||
@include responsive-padding(12px);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: $text-light;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: $accent-color;
|
||||
box-shadow: 0 0 0 3px rgba($accent-color, 0.2);
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: rgba($text-light, 0.5);
|
||||
}
|
||||
|
||||
&--error {
|
||||
border-color: #ef4444;
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 3px rgba(#ef4444, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
&--success {
|
||||
border-color: #10b981;
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 3px rgba(#10b981, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 4px 12px;
|
||||
border-radius: 16px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
&--primary {
|
||||
background: rgba($primary-color, 0.2);
|
||||
color: $primary-color;
|
||||
border: 1px solid rgba($primary-color, 0.3);
|
||||
}
|
||||
|
||||
&--secondary {
|
||||
background: rgba($secondary-color, 0.2);
|
||||
color: $secondary-color;
|
||||
border: 1px solid rgba($secondary-color, 0.3);
|
||||
}
|
||||
|
||||
&--accent {
|
||||
background: rgba($accent-color, 0.2);
|
||||
color: $accent-color;
|
||||
border: 1px solid rgba($accent-color, 0.3);
|
||||
}
|
||||
|
||||
&--success {
|
||||
background: rgba(#10b981, 0.2);
|
||||
color: #10b981;
|
||||
border: 1px solid rgba(#10b981, 0.3);
|
||||
}
|
||||
|
||||
&--error {
|
||||
background: rgba(#ef4444, 0.2);
|
||||
color: #ef4444;
|
||||
border: 1px solid rgba(#ef4444, 0.3);
|
||||
}
|
||||
|
||||
&--warning {
|
||||
background: rgba(#f59e0b, 0.2);
|
||||
color: #f59e0b;
|
||||
border: 1px solid rgba(#f59e0b, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
&-panel {
|
||||
@include responsive-padding(24px);
|
||||
@include elevation(1);
|
||||
border-radius: 12px;
|
||||
background: $background-card;
|
||||
|
||||
&--with-header {
|
||||
padding: 0;
|
||||
|
||||
.panel-header {
|
||||
@include responsive-padding(20px);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
font-weight: 600;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
@include responsive-padding(24px);
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
@include responsive-padding(20px);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-dialog {
|
||||
.dialog-overlay {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
@include elevation(4);
|
||||
border-radius: 16px;
|
||||
background: $background-card;
|
||||
max-width: 600px;
|
||||
animation: dialog-appear 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes dialog-appear {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.95) translateY(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1) translateY(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-tooltip {
|
||||
@include elevation(2);
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
background: $background-card;
|
||||
color: $text-light;
|
||||
font-size: 12px;
|
||||
max-width: 200px;
|
||||
animation: tooltip-appear 0.2s ease;
|
||||
|
||||
@keyframes tooltip-appear {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(4px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-avatar {
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
|
||||
&--small {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
&--medium {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
&--large {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
&--with-ring {
|
||||
box-shadow: 0 0 0 3px $accent-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-badge {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
|
||||
.badge-indicator {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
transform: translate(50%, -50%);
|
||||
min-width: 20px;
|
||||
height: 20px;
|
||||
padding: 0 6px;
|
||||
border-radius: 10px;
|
||||
background: #ef4444;
|
||||
color: white;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2px solid $background-dark;
|
||||
}
|
||||
|
||||
&--dot {
|
||||
.badge-indicator {
|
||||
min-width: 10px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
padding: 0;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-skeleton {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(255, 255, 255, 0.05) 25%,
|
||||
rgba(255, 255, 255, 0.1) 50%,
|
||||
rgba(255, 255, 255, 0.05) 75%
|
||||
);
|
||||
background-size: 200% 100%;
|
||||
animation: skeleton-shimmer 1.5s infinite;
|
||||
border-radius: 4px;
|
||||
|
||||
@keyframes skeleton-shimmer {
|
||||
0% {
|
||||
background-position: 200% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: -200% 0;
|
||||
}
|
||||
}
|
||||
|
||||
&--text {
|
||||
height: 16px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&--circle {
|
||||
border-radius: 50%;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
&--rect {
|
||||
height: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
&-progress {
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
|
||||
.progress-bar {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, $primary-color, $accent-color);
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
&--indeterminate {
|
||||
.progress-bar {
|
||||
width: 40%;
|
||||
animation: progress-indeterminate 1.5s infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes progress-indeterminate {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(350%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-divider {
|
||||
height: 1px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
margin: 16px 0;
|
||||
|
||||
&--vertical {
|
||||
width: 1px;
|
||||
height: auto;
|
||||
margin: 0 16px;
|
||||
}
|
||||
|
||||
&--with-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-accordion {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
|
||||
&-item {
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-trigger {
|
||||
@include responsive-padding(16px);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: $text-light;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.accordion-icon {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
&[data-state='open'] .accordion-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
@include responsive-padding(16px);
|
||||
animation: accordion-slide-down 0.3s ease;
|
||||
|
||||
&[data-state='closed'] {
|
||||
animation: accordion-slide-up 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes accordion-slide-down {
|
||||
from {
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
height: var(--radix-accordion-content-height);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes accordion-slide-up {
|
||||
from {
|
||||
height: var(--radix-accordion-content-height);
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.custom-scrollbar {
|
||||
&::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
* {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user