Add SCSS styles for base, components, layouts, and utilities (not on
use)
This commit is contained in:
181
src/assets/scss/abstracts/_mixins.scss
Normal file
181
src/assets/scss/abstracts/_mixins.scss
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
// Responsive breakpoints
|
||||||
|
@mixin respond-above($breakpoint) {
|
||||||
|
@media (min-width: $breakpoint) {
|
||||||
|
@content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin respond-below($breakpoint) {
|
||||||
|
@media (max-width: #{$breakpoint - 1px}) {
|
||||||
|
@content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flexbox utilities
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grid utilities
|
||||||
|
@mixin grid-responsive($columns-mobile: 1, $columns-tablet: 2, $columns-desktop: 3, $gap: $spacing-md) {
|
||||||
|
display: grid;
|
||||||
|
gap: $gap;
|
||||||
|
grid-template-columns: repeat($columns-mobile, 1fr);
|
||||||
|
|
||||||
|
@include respond-above($breakpoint-md) {
|
||||||
|
grid-template-columns: repeat($columns-tablet, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include respond-above($breakpoint-lg) {
|
||||||
|
grid-template-columns: repeat($columns-desktop, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Button mixins
|
||||||
|
@mixin button-base {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: $radius-md;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all $transition-fast;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin button-primary {
|
||||||
|
@include button-base;
|
||||||
|
background-color: $primary;
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background-color: $primary-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin button-secondary {
|
||||||
|
@include button-base;
|
||||||
|
background-color: $gray-100;
|
||||||
|
color: $gray-700;
|
||||||
|
border: 1px solid $gray-200;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background-color: $gray-200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Card mixins
|
||||||
|
@mixin card-base {
|
||||||
|
background-color: white;
|
||||||
|
border-radius: $radius-2xl;
|
||||||
|
box-shadow: $shadow-sm;
|
||||||
|
border: 1px solid $gray-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin card-padding($size: md) {
|
||||||
|
@if $size == sm {
|
||||||
|
padding: $spacing-md;
|
||||||
|
} @else if $size == md {
|
||||||
|
padding: $spacing-lg;
|
||||||
|
} @else if $size == lg {
|
||||||
|
padding: $spacing-xl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status indicators
|
||||||
|
@mixin status-indicator($color) {
|
||||||
|
width: 0.5rem;
|
||||||
|
height: 0.5rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: $color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sensor type styling
|
||||||
|
@mixin sensor-type-style($bg-color, $text-color) {
|
||||||
|
background-color: $bg-color;
|
||||||
|
color: $text-color;
|
||||||
|
padding: $spacing-sm;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Battery indicator
|
||||||
|
@mixin battery-indicator {
|
||||||
|
height: 0.25rem;
|
||||||
|
background-color: $gray-200;
|
||||||
|
border-radius: 9999px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.fill {
|
||||||
|
height: 100%;
|
||||||
|
border-radius: inherit;
|
||||||
|
transition: all $transition-normal;
|
||||||
|
|
||||||
|
&.good {
|
||||||
|
background-color: $battery-good;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.warning {
|
||||||
|
background-color: $battery-warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.critical {
|
||||||
|
background-color: $battery-critical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom slider
|
||||||
|
@mixin custom-slider {
|
||||||
|
width: 100%;
|
||||||
|
height: 0.5rem;
|
||||||
|
background-color: $gray-200;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
appearance: none;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&::-webkit-slider-thumb {
|
||||||
|
appearance: none;
|
||||||
|
height: 1.25rem;
|
||||||
|
width: 1.25rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: $primary;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-moz-range-thumb {
|
||||||
|
height: 1.25rem;
|
||||||
|
width: 1.25rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: $primary;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Truncate text
|
||||||
|
@mixin truncate {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
83
src/assets/scss/abstracts/_variables.scss
Normal file
83
src/assets/scss/abstracts/_variables.scss
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
// Colors
|
||||||
|
$primary: #3b82f6;
|
||||||
|
$primary-light: #60a5fa;
|
||||||
|
$primary-dark: #2563eb;
|
||||||
|
|
||||||
|
$secondary: #6b7280;
|
||||||
|
$secondary-light: #9ca3af;
|
||||||
|
$secondary-dark: #4b5563;
|
||||||
|
|
||||||
|
$success: #10b981;
|
||||||
|
$warning: #f59e0b;
|
||||||
|
$danger: #ef4444;
|
||||||
|
$info: #06b6d4;
|
||||||
|
|
||||||
|
$gray-50: #f9fafb;
|
||||||
|
$gray-100: #f3f4f6;
|
||||||
|
$gray-200: #e5e7eb;
|
||||||
|
$gray-300: #d1d5db;
|
||||||
|
$gray-400: #9ca3af;
|
||||||
|
$gray-500: #6b7280;
|
||||||
|
$gray-600: #4b5563;
|
||||||
|
$gray-700: #374151;
|
||||||
|
$gray-800: #1f2937;
|
||||||
|
$gray-900: #111827;
|
||||||
|
|
||||||
|
// Status Colors
|
||||||
|
$status-online: #10b981;
|
||||||
|
$status-offline: #6b7280;
|
||||||
|
$status-error: #ef4444;
|
||||||
|
|
||||||
|
// Sensor Type Colors
|
||||||
|
$sensor-energy-bg: #fef3c7;
|
||||||
|
$sensor-energy-text: #b45309;
|
||||||
|
$sensor-co2-bg: #dcfce7;
|
||||||
|
$sensor-co2-text: #166534;
|
||||||
|
$sensor-temperature-bg: #fee2e2;
|
||||||
|
$sensor-temperature-text: #991b1b;
|
||||||
|
$sensor-humidity-bg: #dbeafe;
|
||||||
|
$sensor-humidity-text: #1e40af;
|
||||||
|
$sensor-hvac-bg: #cffafe;
|
||||||
|
$sensor-hvac-text: #155e75;
|
||||||
|
$sensor-lighting-bg: #fef3c7;
|
||||||
|
$sensor-lighting-text: #92400e;
|
||||||
|
$sensor-security-bg: #f3e8ff;
|
||||||
|
$sensor-security-text: #7c2d12;
|
||||||
|
|
||||||
|
// Battery Colors
|
||||||
|
$battery-good: #10b981;
|
||||||
|
$battery-warning: #f59e0b;
|
||||||
|
$battery-critical: #ef4444;
|
||||||
|
|
||||||
|
// Spacing
|
||||||
|
$spacing-xs: 0.25rem;
|
||||||
|
$spacing-sm: 0.5rem;
|
||||||
|
$spacing-md: 1rem;
|
||||||
|
$spacing-lg: 1.5rem;
|
||||||
|
$spacing-xl: 2rem;
|
||||||
|
$spacing-2xl: 3rem;
|
||||||
|
|
||||||
|
// Border Radius
|
||||||
|
$radius-sm: 0.375rem;
|
||||||
|
$radius-md: 0.5rem;
|
||||||
|
$radius-lg: 0.75rem;
|
||||||
|
$radius-xl: 1rem;
|
||||||
|
$radius-2xl: 1.5rem;
|
||||||
|
|
||||||
|
// Shadows
|
||||||
|
$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);
|
||||||
|
|
||||||
|
// Transitions
|
||||||
|
$transition-fast: 150ms ease-in-out;
|
||||||
|
$transition-normal: 300ms ease-in-out;
|
||||||
|
$transition-slow: 500ms ease-in-out;
|
||||||
|
|
||||||
|
// Breakpoints
|
||||||
|
$breakpoint-sm: 640px;
|
||||||
|
$breakpoint-md: 768px;
|
||||||
|
$breakpoint-lg: 1024px;
|
||||||
|
$breakpoint-xl: 1280px;
|
||||||
|
$breakpoint-2xl: 1536px;
|
||||||
34
src/assets/scss/base/_reset.scss
Normal file
34
src/assets/scss/base/_reset.scss
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// CSS Reset and Base Styles
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
line-height: 1.15;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family:
|
||||||
|
ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
||||||
|
'Noto Color Emoji';
|
||||||
|
background-color: $gray-100;
|
||||||
|
color: $gray-900;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
56
src/assets/scss/base/_typography.scss
Normal file
56
src/assets/scss/base/_typography.scss
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// Typography Styles
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h6 {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text utilities
|
||||||
|
.text-xs { font-size: 0.75rem; }
|
||||||
|
.text-sm { font-size: 0.875rem; }
|
||||||
|
.text-base { font-size: 1rem; }
|
||||||
|
.text-lg { font-size: 1.125rem; }
|
||||||
|
.text-xl { font-size: 1.25rem; }
|
||||||
|
.text-2xl { font-size: 1.5rem; }
|
||||||
|
|
||||||
|
.font-medium { font-weight: 500; }
|
||||||
|
.font-semibold { font-weight: 600; }
|
||||||
|
.font-bold { font-weight: 700; }
|
||||||
|
|
||||||
|
.text-center { text-align: center; }
|
||||||
|
.text-left { text-align: left; }
|
||||||
|
.text-right { text-align: right; }
|
||||||
133
src/assets/scss/components/_buttons.scss
Normal file
133
src/assets/scss/components/_buttons.scss
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
// Button Base Styles
|
||||||
|
.btn {
|
||||||
|
@include button-base;
|
||||||
|
padding: $spacing-sm $spacing-md;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
|
||||||
|
&--primary {
|
||||||
|
@include button-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--secondary {
|
||||||
|
@include button-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--sm {
|
||||||
|
padding: $spacing-xs $spacing-sm;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--md {
|
||||||
|
padding: $spacing-sm $spacing-md;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--lg {
|
||||||
|
padding: $spacing-md $spacing-lg;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--icon-only {
|
||||||
|
padding: $spacing-sm;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle Button Group
|
||||||
|
.toggle-group {
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-sm;
|
||||||
|
background-color: $gray-100;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
padding: $spacing-xs;
|
||||||
|
|
||||||
|
.toggle-btn {
|
||||||
|
padding: $spacing-sm * 1.5 $spacing-md;
|
||||||
|
border-radius: $radius-md;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all $transition-fast;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-xs;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: white;
|
||||||
|
color: $gray-900;
|
||||||
|
box-shadow: $shadow-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.inactive {
|
||||||
|
color: $gray-600;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $gray-900;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action Buttons
|
||||||
|
.action-button {
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-sm;
|
||||||
|
padding: $spacing-sm $spacing-md;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all $transition-fast;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid $gray-200;
|
||||||
|
background-color: $gray-50;
|
||||||
|
color: $gray-700;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background-color: $gray-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
@include truncate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close Button
|
||||||
|
.close-button {
|
||||||
|
padding: $spacing-sm;
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: background-color $transition-fast;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $gray-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
color: $gray-400;
|
||||||
|
}
|
||||||
|
}
|
||||||
452
src/assets/scss/components/_cards.scss
Normal file
452
src/assets/scss/components/_cards.scss
Normal file
@@ -0,0 +1,452 @@
|
|||||||
|
// Base Card Styles
|
||||||
|
.card {
|
||||||
|
@include card-base;
|
||||||
|
|
||||||
|
&--padding-sm {
|
||||||
|
@include card-padding(sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--padding-md {
|
||||||
|
@include card-padding(md);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--padding-lg {
|
||||||
|
@include card-padding(lg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple Sensor Card
|
||||||
|
.simple-sensor-card {
|
||||||
|
@include card-base;
|
||||||
|
@include card-padding(md);
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
@include flex-between;
|
||||||
|
margin-bottom: $spacing-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__info {
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-sm;
|
||||||
|
|
||||||
|
.icon-container {
|
||||||
|
padding: $spacing-sm * 1.5;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.details {
|
||||||
|
h3 {
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-900;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: $gray-500;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__status {
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-xs;
|
||||||
|
|
||||||
|
.indicator {
|
||||||
|
@include status-indicator($status-offline);
|
||||||
|
|
||||||
|
&--online {
|
||||||
|
background-color: $status-online;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--offline {
|
||||||
|
background-color: $status-offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--error {
|
||||||
|
background-color: $status-error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: $gray-500;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__values {
|
||||||
|
margin-bottom: $spacing-md;
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: $spacing-sm;
|
||||||
|
|
||||||
|
.metric {
|
||||||
|
background-color: $gray-50;
|
||||||
|
border-radius: $radius-md;
|
||||||
|
padding: $spacing-sm;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
color: $gray-600;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
margin-bottom: $spacing-xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-900;
|
||||||
|
|
||||||
|
.unit {
|
||||||
|
color: $gray-500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__actions {
|
||||||
|
.title {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-600;
|
||||||
|
margin-bottom: $spacing-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: $spacing-xs;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-xs;
|
||||||
|
padding: $spacing-xs $spacing-sm;
|
||||||
|
background-color: $gray-100;
|
||||||
|
color: $gray-700;
|
||||||
|
border-radius: $radius-md;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all $transition-fast;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background-color: $gray-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
@include truncate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.more-btn {
|
||||||
|
@extend .action-btn;
|
||||||
|
background-color: #dbeafe;
|
||||||
|
color: #1e40af;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background-color: #bfdbfe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__monitor-only {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: $gray-500;
|
||||||
|
text-align: center;
|
||||||
|
padding: $spacing-sm;
|
||||||
|
background-color: $gray-50;
|
||||||
|
border-radius: $radius-md;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detailed Sensor Card
|
||||||
|
.detailed-sensor-card {
|
||||||
|
@include card-base;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
@include card-padding(md);
|
||||||
|
border-bottom: 1px solid $gray-100;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
@include flex-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-md;
|
||||||
|
|
||||||
|
.icon-container {
|
||||||
|
padding: $spacing-sm;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.details {
|
||||||
|
h3 {
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-900;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: $gray-500;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-sm;
|
||||||
|
|
||||||
|
.indicator {
|
||||||
|
@include status-indicator($status-offline);
|
||||||
|
|
||||||
|
&--online {
|
||||||
|
background-color: $status-online;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--offline {
|
||||||
|
background-color: $status-offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--error {
|
||||||
|
background-color: $status-error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: $gray-500;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
@include card-padding(md);
|
||||||
|
|
||||||
|
.space-y-4 > * + * {
|
||||||
|
margin-top: $spacing-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-700;
|
||||||
|
margin-bottom: $spacing-sm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__room-select {
|
||||||
|
width: 100%;
|
||||||
|
padding: $spacing-md;
|
||||||
|
border: 1px solid $gray-200;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
background-color: white;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: $spacing-xs;
|
||||||
|
margin-bottom: $spacing-sm;
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
padding: $spacing-xs $spacing-sm;
|
||||||
|
background-color: $gray-100;
|
||||||
|
color: $gray-700;
|
||||||
|
border-radius: 9999px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__capabilities {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: $spacing-xs;
|
||||||
|
|
||||||
|
.capability {
|
||||||
|
padding: $spacing-xs $spacing-sm;
|
||||||
|
background-color: #dbeafe;
|
||||||
|
color: #1e40af;
|
||||||
|
border-radius: $radius-md;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__values-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: $spacing-sm;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
|
||||||
|
.metric {
|
||||||
|
background-color: $gray-50;
|
||||||
|
border-radius: $radius-md;
|
||||||
|
padding: $spacing-sm;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
color: $gray-600;
|
||||||
|
margin-bottom: $spacing-xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-900;
|
||||||
|
|
||||||
|
.unit {
|
||||||
|
color: $gray-500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__device-info {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: $spacing-sm;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: $gray-600;
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
.label {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
margin-top: $spacing-xs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.battery-info {
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-xs;
|
||||||
|
|
||||||
|
.battery-bar {
|
||||||
|
@include battery-indicator;
|
||||||
|
width: 0.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.signal-info {
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-xs;
|
||||||
|
|
||||||
|
.signal-bars {
|
||||||
|
display: flex;
|
||||||
|
gap: 1px;
|
||||||
|
|
||||||
|
.bar {
|
||||||
|
width: $spacing-xs;
|
||||||
|
height: $spacing-sm;
|
||||||
|
background-color: $gray-200;
|
||||||
|
border-radius: 1px;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: $status-online;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__actions-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: $spacing-sm;
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-sm;
|
||||||
|
padding: $spacing-md;
|
||||||
|
background-color: $gray-50;
|
||||||
|
border: 1px solid $gray-200;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-700;
|
||||||
|
transition: all $transition-fast;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background-color: $gray-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
@include truncate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__no-actions {
|
||||||
|
.placeholder {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: $gray-500;
|
||||||
|
text-align: center;
|
||||||
|
padding: $spacing-md;
|
||||||
|
background-color: $gray-50;
|
||||||
|
border: 2px dashed $gray-200;
|
||||||
|
border-radius: $radius-md;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sensor Type Specific Styles
|
||||||
|
.sensor-energy {
|
||||||
|
@include sensor-type-style($sensor-energy-bg, $sensor-energy-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sensor-co2 {
|
||||||
|
@include sensor-type-style($sensor-co2-bg, $sensor-co2-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sensor-temperature {
|
||||||
|
@include sensor-type-style($sensor-temperature-bg, $sensor-temperature-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sensor-humidity {
|
||||||
|
@include sensor-type-style($sensor-humidity-bg, $sensor-humidity-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sensor-hvac {
|
||||||
|
@include sensor-type-style($sensor-hvac-bg, $sensor-hvac-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sensor-lighting {
|
||||||
|
@include sensor-type-style($sensor-lighting-bg, $sensor-lighting-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sensor-security {
|
||||||
|
@include sensor-type-style($sensor-security-bg, $sensor-security-text);
|
||||||
|
}
|
||||||
47
src/assets/scss/components/_forms.scss
Normal file
47
src/assets/scss/components/_forms.scss
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// Form Elements
|
||||||
|
.form-select {
|
||||||
|
padding: $spacing-sm $spacing-md;
|
||||||
|
border: 1px solid $gray-200;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
background-color: white;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
transition: border-color $transition-fast;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: $primary;
|
||||||
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-input {
|
||||||
|
padding: $spacing-sm $spacing-md;
|
||||||
|
border: 1px solid $gray-200;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
background-color: white;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
transition: border-color $transition-fast;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: $primary;
|
||||||
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-700;
|
||||||
|
margin-bottom: $spacing-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom Range Input
|
||||||
|
.range-slider {
|
||||||
|
@include custom-slider;
|
||||||
|
}
|
||||||
256
src/assets/scss/components/_modals.scss
Normal file
256
src/assets/scss/components/_modals.scss
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
// Action Modal Styles
|
||||||
|
.action-modal {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 50;
|
||||||
|
@include flex-center;
|
||||||
|
|
||||||
|
&__backdrop {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__container {
|
||||||
|
position: relative;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: $radius-2xl;
|
||||||
|
box-shadow: $shadow-xl;
|
||||||
|
max-width: 28rem;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 $spacing-md;
|
||||||
|
max-height: 90vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
padding: $spacing-xl;
|
||||||
|
border-bottom: 1px solid $gray-100;
|
||||||
|
@include flex-between;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-900;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: $gray-600;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__close-button {
|
||||||
|
padding: $spacing-sm;
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: background-color $transition-fast;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $gray-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
color: $gray-400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
padding: $spacing-xl;
|
||||||
|
|
||||||
|
.space-y-4 > * + * {
|
||||||
|
margin-top: $spacing-md;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footer {
|
||||||
|
padding: $spacing-xl $spacing-xl $spacing-md;
|
||||||
|
background-color: $gray-50;
|
||||||
|
border-radius: 0 0 $radius-2xl $radius-2xl;
|
||||||
|
display: flex;
|
||||||
|
gap: $spacing-md;
|
||||||
|
|
||||||
|
button {
|
||||||
|
flex: 1;
|
||||||
|
padding: $spacing-sm $spacing-md;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all $transition-fast;
|
||||||
|
|
||||||
|
&.cancel {
|
||||||
|
@include button-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.execute {
|
||||||
|
@include button-primary;
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background-color: #93c5fd;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range Input Styling
|
||||||
|
.range-input {
|
||||||
|
&__container {
|
||||||
|
.space-y-3 > * + * {
|
||||||
|
margin-top: $spacing-md;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__slider {
|
||||||
|
@include custom-slider;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__labels {
|
||||||
|
@include flex-between;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: $gray-600;
|
||||||
|
|
||||||
|
.current-value {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-700;
|
||||||
|
margin-bottom: $spacing-sm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option Selection
|
||||||
|
.option-selection {
|
||||||
|
&__label {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-700;
|
||||||
|
margin-bottom: $spacing-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: $spacing-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__button {
|
||||||
|
padding: $spacing-md;
|
||||||
|
border: 1px solid $gray-200;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all $transition-fast;
|
||||||
|
cursor: pointer;
|
||||||
|
background: white;
|
||||||
|
color: $gray-700;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $gray-50;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
background-color: $primary;
|
||||||
|
color: white;
|
||||||
|
border-color: $primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle Control
|
||||||
|
.toggle-control {
|
||||||
|
@include flex-between;
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-700;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__switch {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
height: 1.5rem;
|
||||||
|
width: 2.75rem;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 9999px;
|
||||||
|
transition: background-color $transition-fast;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
&.on {
|
||||||
|
background-color: $primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.off {
|
||||||
|
background-color: $gray-200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__thumb {
|
||||||
|
display: inline-block;
|
||||||
|
height: 1rem;
|
||||||
|
width: 1rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: white;
|
||||||
|
transition: transform $transition-fast;
|
||||||
|
|
||||||
|
&.on {
|
||||||
|
transform: translateX(1.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.off {
|
||||||
|
transform: translateX(0.25rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__status {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: $gray-500;
|
||||||
|
margin-top: $spacing-xs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger Action
|
||||||
|
.trigger-action {
|
||||||
|
&__container {
|
||||||
|
background-color: $gray-50;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
padding: $spacing-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-md;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
.title {
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-900;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: $gray-600;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/assets/scss/layouts/_dashboard.scss
Normal file
27
src/assets/scss/layouts/_dashboard.scss
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// Dashboard Layout
|
||||||
|
.dashboard {
|
||||||
|
&__container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: $spacing-md;
|
||||||
|
|
||||||
|
@include respond-above($breakpoint-sm) {
|
||||||
|
padding: $spacing-lg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__main {
|
||||||
|
flex-grow: 1;
|
||||||
|
padding-bottom: 5rem; // Space for bottom nav on mobile
|
||||||
|
|
||||||
|
@include respond-above($breakpoint-md) {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
.space-y-6 > * + * {
|
||||||
|
margin-top: $spacing-xl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/assets/scss/layouts/_grid.scss
Normal file
52
src/assets/scss/layouts/_grid.scss
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// Grid Layouts
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
|
||||||
|
&--1 { grid-template-columns: 1fr; }
|
||||||
|
&--2 { grid-template-columns: repeat(2, 1fr); }
|
||||||
|
&--3 { grid-template-columns: repeat(3, 1fr); }
|
||||||
|
&--4 { grid-template-columns: repeat(4, 1fr); }
|
||||||
|
|
||||||
|
&--gap-2 { gap: $spacing-sm; }
|
||||||
|
&--gap-4 { gap: $spacing-md; }
|
||||||
|
&--gap-6 { gap: $spacing-lg; }
|
||||||
|
|
||||||
|
// Responsive grids
|
||||||
|
&--responsive-simple {
|
||||||
|
@include grid-responsive(1, 3, 4, $spacing-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--responsive-detailed {
|
||||||
|
@include grid-responsive(1, 2, 3, $spacing-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--responsive-cards {
|
||||||
|
@include grid-responsive(1, 2, 3, $spacing-md);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flexbox utilities
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
&--center {
|
||||||
|
@include flex-center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--between {
|
||||||
|
@include flex-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--column {
|
||||||
|
@include flex-column;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--wrap {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--gap-1 { gap: $spacing-xs; }
|
||||||
|
&--gap-2 { gap: $spacing-sm; }
|
||||||
|
&--gap-3 { gap: $spacing-md; }
|
||||||
|
&--gap-4 { gap: $spacing-lg; }
|
||||||
|
}
|
||||||
23
src/assets/scss/main.scss
Normal file
23
src/assets/scss/main.scss
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
@use 'tailwindcss';
|
||||||
|
@import 'abstracts/variables';
|
||||||
|
@import 'abstracts/mixins';
|
||||||
|
|
||||||
|
@import 'base/reset';
|
||||||
|
@import 'base/typography';
|
||||||
|
|
||||||
|
@import 'components/buttons';
|
||||||
|
@import 'components/cards';
|
||||||
|
@import 'components/forms';
|
||||||
|
@import 'components/modals';
|
||||||
|
|
||||||
|
@import 'layouts/grid';
|
||||||
|
@import 'layouts/dashboard';
|
||||||
|
|
||||||
|
@import 'pages/sensor-management';
|
||||||
|
@import 'pages/home';
|
||||||
|
|
||||||
|
@import 'utilities/helpers';
|
||||||
|
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
167
src/assets/scss/pages/_home.scss
Normal file
167
src/assets/scss/pages/_home.scss
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
// Home Dashboard Page
|
||||||
|
.home-dashboard {
|
||||||
|
&__filters {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $spacing-md;
|
||||||
|
margin-bottom: $spacing-xl;
|
||||||
|
|
||||||
|
@include respond-above($breakpoint-sm) {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-select {
|
||||||
|
@extend .form-select;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__metrics-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: $spacing-md;
|
||||||
|
min-height: 24rem;
|
||||||
|
|
||||||
|
@include respond-above($breakpoint-lg) {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metrics-grid {
|
||||||
|
@include grid-responsive(1, 2, 3, $spacing-md);
|
||||||
|
|
||||||
|
@include respond-above($breakpoint-lg) {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
|
||||||
|
@include respond-above($breakpoint-lg) {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
// Chart styling handled by chart library
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__charts-row {
|
||||||
|
@include grid-responsive(1, 2, 2, $spacing-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__topics-row {
|
||||||
|
@include grid-responsive(1, 2, 2, $spacing-md);
|
||||||
|
|
||||||
|
.topic-card {
|
||||||
|
@include card-base;
|
||||||
|
@include card-padding(md);
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $gray-500;
|
||||||
|
margin-bottom: $spacing-sm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__leaderboards-row {
|
||||||
|
@include grid-responsive(1, 2, 2, $spacing-md);
|
||||||
|
|
||||||
|
.leaderboard-card {
|
||||||
|
@include card-base;
|
||||||
|
@include card-padding(md);
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $gray-500;
|
||||||
|
margin-bottom: $spacing-sm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metric Cards
|
||||||
|
.metric-card {
|
||||||
|
@include card-base;
|
||||||
|
@include card-padding(md);
|
||||||
|
@include flex-column;
|
||||||
|
justify-content: space-between;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $gray-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-section {
|
||||||
|
flex-grow: 1;
|
||||||
|
@include flex-center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
.value {
|
||||||
|
color: $gray-900;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
|
||||||
|
.unit {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: $gray-500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Graph Metric Cards
|
||||||
|
.graph-metric-card {
|
||||||
|
@include card-base;
|
||||||
|
@include card-padding(md);
|
||||||
|
|
||||||
|
.header {
|
||||||
|
@include flex-between;
|
||||||
|
margin-bottom: $spacing-md;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $gray-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trend-indicator {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
padding: $spacing-xs $spacing-sm;
|
||||||
|
border-radius: $radius-md;
|
||||||
|
|
||||||
|
&--up {
|
||||||
|
background-color: #dcfce7;
|
||||||
|
color: #166534;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--down {
|
||||||
|
background-color: #fee2e2;
|
||||||
|
color: #991b1b;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--neutral {
|
||||||
|
background-color: $gray-100;
|
||||||
|
color: $gray-600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $gray-900;
|
||||||
|
margin-bottom: $spacing-sm;
|
||||||
|
|
||||||
|
.unit {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: $gray-500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
height: 2rem;
|
||||||
|
// Chart styling handled by chart library
|
||||||
|
}
|
||||||
|
}
|
||||||
114
src/assets/scss/pages/_sensor-management.scss
Normal file
114
src/assets/scss/pages/_sensor-management.scss
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
// Sensor Management Page
|
||||||
|
.sensor-management {
|
||||||
|
&__header {
|
||||||
|
@include flex-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
@include respond-above($breakpoint-sm) {
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-section {
|
||||||
|
h1 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $gray-900;
|
||||||
|
margin-bottom: $spacing-xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: $gray-600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-section {
|
||||||
|
margin-top: $spacing-md;
|
||||||
|
|
||||||
|
@include respond-above($breakpoint-sm) {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-info {
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-sm;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: $gray-600;
|
||||||
|
|
||||||
|
.connection-indicator {
|
||||||
|
@include status-indicator($status-offline);
|
||||||
|
|
||||||
|
&--connected {
|
||||||
|
background-color: $status-online;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--disconnected {
|
||||||
|
background-color: $status-error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
margin: 0 $spacing-sm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__filters {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $spacing-md;
|
||||||
|
|
||||||
|
@include respond-above($breakpoint-lg) {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $spacing-md;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
@include respond-above($breakpoint-sm) {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-toggle {
|
||||||
|
@extend .toggle-group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__grid {
|
||||||
|
&--simple {
|
||||||
|
@include grid-responsive(1, 3, 4, $spacing-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--detailed {
|
||||||
|
@include grid-responsive(1, 2, 3, $spacing-lg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__empty-state {
|
||||||
|
text-align: center;
|
||||||
|
padding: $spacing-2xl * 2;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
color: $gray-400;
|
||||||
|
font-size: 3.75rem;
|
||||||
|
margin-bottom: $spacing-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-900;
|
||||||
|
margin-bottom: $spacing-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
color: $gray-600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
109
src/assets/scss/utilities/_helpers.scss
Normal file
109
src/assets/scss/utilities/_helpers.scss
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
// Utility Classes
|
||||||
|
.sr-only {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spacing utilities
|
||||||
|
.space-y-2 > * + * { margin-top: $spacing-sm; }
|
||||||
|
.space-y-3 > * + * { margin-top: $spacing-md; }
|
||||||
|
.space-y-4 > * + * { margin-top: $spacing-lg; }
|
||||||
|
.space-y-6 > * + * { margin-top: $spacing-xl; }
|
||||||
|
|
||||||
|
.space-x-2 > * + * { margin-left: $spacing-sm; }
|
||||||
|
.space-x-3 > * + * { margin-left: $spacing-md; }
|
||||||
|
.space-x-4 > * + * { margin-left: $spacing-lg; }
|
||||||
|
|
||||||
|
// Margin utilities
|
||||||
|
.m-0 { margin: 0; }
|
||||||
|
.mb-1 { margin-bottom: $spacing-xs; }
|
||||||
|
.mb-2 { margin-bottom: $spacing-sm; }
|
||||||
|
.mb-3 { margin-bottom: $spacing-md; }
|
||||||
|
.mb-4 { margin-bottom: $spacing-lg; }
|
||||||
|
|
||||||
|
.mt-1 { margin-top: $spacing-xs; }
|
||||||
|
.mt-2 { margin-top: $spacing-sm; }
|
||||||
|
.mt-3 { margin-top: $spacing-md; }
|
||||||
|
.mt-4 { margin-top: $spacing-lg; }
|
||||||
|
|
||||||
|
// Padding utilities
|
||||||
|
.p-0 { padding: 0; }
|
||||||
|
.p-1 { padding: $spacing-xs; }
|
||||||
|
.p-2 { padding: $spacing-sm; }
|
||||||
|
.p-3 { padding: $spacing-md; }
|
||||||
|
.p-4 { padding: $spacing-lg; }
|
||||||
|
|
||||||
|
// Width utilities
|
||||||
|
.w-full { width: 100%; }
|
||||||
|
.w-auto { width: auto; }
|
||||||
|
|
||||||
|
// Height utilities
|
||||||
|
.h-full { height: 100%; }
|
||||||
|
.h-auto { height: auto; }
|
||||||
|
|
||||||
|
// Color utilities
|
||||||
|
.text-primary { color: $primary; }
|
||||||
|
.text-secondary { color: $secondary; }
|
||||||
|
.text-success { color: $success; }
|
||||||
|
.text-warning { color: $warning; }
|
||||||
|
.text-danger { color: $danger; }
|
||||||
|
|
||||||
|
.text-gray-400 { color: $gray-400; }
|
||||||
|
.text-gray-500 { color: $gray-500; }
|
||||||
|
.text-gray-600 { color: $gray-600; }
|
||||||
|
.text-gray-700 { color: $gray-700; }
|
||||||
|
.text-gray-900 { color: $gray-900; }
|
||||||
|
|
||||||
|
// Background utilities
|
||||||
|
.bg-primary { background-color: $primary; }
|
||||||
|
.bg-white { background-color: white; }
|
||||||
|
.bg-gray-50 { background-color: $gray-50; }
|
||||||
|
.bg-gray-100 { background-color: $gray-100; }
|
||||||
|
|
||||||
|
// Border utilities
|
||||||
|
.border { border: 1px solid $gray-200; }
|
||||||
|
.border-0 { border: 0; }
|
||||||
|
.border-gray-100 { border-color: $gray-100; }
|
||||||
|
.border-gray-200 { border-color: $gray-200; }
|
||||||
|
|
||||||
|
// Border radius utilities
|
||||||
|
.rounded { border-radius: $radius-md; }
|
||||||
|
.rounded-lg { border-radius: $radius-lg; }
|
||||||
|
.rounded-xl { border-radius: $radius-xl; }
|
||||||
|
.rounded-2xl { border-radius: $radius-2xl; }
|
||||||
|
.rounded-full { border-radius: 9999px; }
|
||||||
|
|
||||||
|
// Shadow utilities
|
||||||
|
.shadow-sm { box-shadow: $shadow-sm; }
|
||||||
|
.shadow-md { box-shadow: $shadow-md; }
|
||||||
|
.shadow-lg { box-shadow: $shadow-lg; }
|
||||||
|
.shadow-xl { box-shadow: $shadow-xl; }
|
||||||
|
|
||||||
|
// Position utilities
|
||||||
|
.relative { position: relative; }
|
||||||
|
.absolute { position: absolute; }
|
||||||
|
.fixed { position: fixed; }
|
||||||
|
|
||||||
|
// Z-index utilities
|
||||||
|
.z-10 { z-index: 10; }
|
||||||
|
.z-20 { z-index: 20; }
|
||||||
|
.z-50 { z-index: 50; }
|
||||||
|
|
||||||
|
// Overflow utilities
|
||||||
|
.overflow-hidden { overflow: hidden; }
|
||||||
|
.overflow-y-auto { overflow-y: auto; }
|
||||||
|
|
||||||
|
// Cursor utilities
|
||||||
|
.cursor-pointer { cursor: pointer; }
|
||||||
|
.cursor-not-allowed { cursor: not-allowed; }
|
||||||
|
|
||||||
|
// Opacity utilities
|
||||||
|
.opacity-50 { opacity: 0.5; }
|
||||||
|
.opacity-75 { opacity: 0.75; }
|
||||||
Reference in New Issue
Block a user