547 lines
9.1 KiB
CSS
547 lines
9.1 KiB
CSS
/* Custom CSS untuk FTTH Planner */
|
|
|
|
/* Map Styles */
|
|
#map {
|
|
border-radius: 0;
|
|
border: none;
|
|
}
|
|
|
|
.leaflet-popup-content {
|
|
margin: 8px 15px;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
.leaflet-popup-content h5 {
|
|
margin: 0 0 5px 0;
|
|
color: #007bff;
|
|
}
|
|
|
|
.popup-info {
|
|
font-size: 13px;
|
|
}
|
|
|
|
.popup-info .info-row {
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
|
|
.popup-info .info-label {
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
|
|
.popup-actions {
|
|
margin-top: 10px;
|
|
text-align: center;
|
|
}
|
|
|
|
.popup-actions .btn {
|
|
margin: 2px;
|
|
padding: 5px 10px;
|
|
font-size: 12px;
|
|
}
|
|
|
|
/* Custom marker icons */
|
|
.custom-marker {
|
|
border-radius: 50%;
|
|
border: 3px solid white;
|
|
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
|
|
}
|
|
|
|
.marker-olt {
|
|
background-color: #FF6B6B;
|
|
}
|
|
|
|
.marker-tiang {
|
|
background-color: #4ECDC4;
|
|
}
|
|
|
|
.marker-odp {
|
|
background-color: #45B7D1;
|
|
}
|
|
|
|
.marker-odc {
|
|
background-color: #96CEB4;
|
|
}
|
|
|
|
.marker-pelanggan {
|
|
background-color: #FFA500;
|
|
}
|
|
|
|
/* Modal styles */
|
|
.modal-header {
|
|
background-color: #007bff;
|
|
color: white;
|
|
}
|
|
|
|
.modal-header .close {
|
|
color: white;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.modal-header .close:hover {
|
|
opacity: 1;
|
|
}
|
|
|
|
/* Form styles */
|
|
.form-group label {
|
|
font-weight: 600;
|
|
color: #333;
|
|
}
|
|
|
|
.tube-color-option {
|
|
display: inline-block;
|
|
width: 20px;
|
|
height: 20px;
|
|
margin-right: 8px;
|
|
vertical-align: middle;
|
|
border-radius: 3px;
|
|
border: 1px solid #ddd;
|
|
}
|
|
|
|
/* Routing styles */
|
|
.routing-mode {
|
|
cursor: crosshair !important;
|
|
}
|
|
|
|
.route-line {
|
|
stroke-width: 4;
|
|
stroke-opacity: 0.8;
|
|
}
|
|
|
|
.route-installed {
|
|
stroke: #28a745;
|
|
}
|
|
|
|
.route-planned {
|
|
stroke: #ffc107;
|
|
stroke-dasharray: 10, 5;
|
|
}
|
|
|
|
.route-maintenance {
|
|
stroke: #dc3545;
|
|
stroke-dasharray: 5, 5;
|
|
}
|
|
|
|
/* Statistics cards */
|
|
.small-box {
|
|
border-radius: 10px;
|
|
}
|
|
|
|
.small-box .icon {
|
|
font-size: 60px;
|
|
}
|
|
|
|
/* Sidebar brand */
|
|
.brand-link {
|
|
border-bottom: 1px solid #4f5962;
|
|
}
|
|
|
|
.brand-link:hover {
|
|
text-decoration: none;
|
|
}
|
|
|
|
/* Loading spinner */
|
|
.loading-spinner {
|
|
display: inline-block;
|
|
width: 20px;
|
|
height: 20px;
|
|
border: 3px solid rgba(255,255,255,.3);
|
|
border-radius: 50%;
|
|
border-top-color: #fff;
|
|
animation: spin 1s ease-in-out infinite;
|
|
}
|
|
|
|
@keyframes spin {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
|
|
/* Responsive adjustments */
|
|
@media (max-width: 768px) {
|
|
#map {
|
|
height: 400px !important;
|
|
}
|
|
|
|
.modal-dialog {
|
|
margin: 10px;
|
|
}
|
|
|
|
.popup-actions .btn {
|
|
display: block;
|
|
width: 100%;
|
|
margin: 3px 0;
|
|
}
|
|
}
|
|
|
|
/* Drag and drop indicators */
|
|
.item-dragging {
|
|
opacity: 0.7;
|
|
transform: scale(1.1);
|
|
z-index: 1000;
|
|
}
|
|
|
|
.drop-zone {
|
|
border: 2px dashed #007bff;
|
|
background-color: rgba(0, 123, 255, 0.1);
|
|
}
|
|
|
|
/* Route drawing mode */
|
|
.route-drawing .leaflet-container {
|
|
cursor: crosshair;
|
|
}
|
|
|
|
.route-point {
|
|
background-color: #ff6b6b;
|
|
border: 2px solid white;
|
|
border-radius: 50%;
|
|
width: 12px;
|
|
height: 12px;
|
|
}
|
|
|
|
/* Notifications */
|
|
.toast {
|
|
min-width: 300px;
|
|
}
|
|
|
|
.toast-header {
|
|
background-color: #007bff;
|
|
color: white;
|
|
}
|
|
|
|
/* Map controls */
|
|
.map-controls {
|
|
position: absolute;
|
|
top: 10px;
|
|
right: 10px;
|
|
z-index: 1000;
|
|
}
|
|
|
|
.map-controls .btn-group-vertical .btn {
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
/* Legend */
|
|
.map-legend {
|
|
background: white;
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
|
position: absolute;
|
|
bottom: 10px;
|
|
left: 10px;
|
|
z-index: 1000;
|
|
max-width: 200px;
|
|
}
|
|
|
|
.legend-item {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.legend-icon {
|
|
width: 20px;
|
|
height: 20px;
|
|
margin-right: 8px;
|
|
border-radius: 50%;
|
|
border: 2px solid white;
|
|
box-shadow: 0 1px 3px rgba(0,0,0,0.3);
|
|
}
|
|
|
|
/* Enhanced Map Controls */
|
|
.leaflet-control-zoom {
|
|
border: none !important;
|
|
border-radius: 5px !important;
|
|
box-shadow: 0 2px 10px rgba(0,0,0,0.2) !important;
|
|
}
|
|
|
|
.leaflet-control-zoom a {
|
|
background-color: #fff !important;
|
|
border: none !important;
|
|
color: #333 !important;
|
|
font-weight: bold;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.leaflet-control-zoom a:hover {
|
|
background-color: #007bff !important;
|
|
color: white !important;
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
.leaflet-control-custom {
|
|
border-radius: 3px !important;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.leaflet-control-custom:hover {
|
|
background-color: #007bff !important;
|
|
color: white !important;
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
.leaflet-control-custom i {
|
|
color: #333;
|
|
transition: color 0.3s ease;
|
|
}
|
|
|
|
.leaflet-control-custom:hover i {
|
|
color: white !important;
|
|
}
|
|
|
|
/* Layer Control Styling */
|
|
.leaflet-control-layers {
|
|
border-radius: 8px !important;
|
|
box-shadow: 0 2px 15px rgba(0,0,0,0.2) !important;
|
|
background: white !important;
|
|
padding: 8px !important;
|
|
}
|
|
|
|
.leaflet-control-layers-toggle {
|
|
background-image: none !important;
|
|
color: #333 !important;
|
|
font-size: 18px;
|
|
}
|
|
|
|
.leaflet-control-layers-expanded {
|
|
padding: 12px !important;
|
|
}
|
|
|
|
.leaflet-control-layers label {
|
|
font-weight: 500;
|
|
margin: 5px 0;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.leaflet-control-layers input[type="radio"] {
|
|
margin-right: 8px;
|
|
}
|
|
|
|
/* Coordinates Control */
|
|
.leaflet-control-coords {
|
|
font-family: 'Courier New', monospace;
|
|
border-radius: 3px;
|
|
border: 1px solid #ccc;
|
|
box-shadow: 0 1px 5px rgba(0,0,0,0.2);
|
|
}
|
|
|
|
/* Scale Control */
|
|
.leaflet-control-scale {
|
|
margin-bottom: 40px !important;
|
|
}
|
|
|
|
/* Help Control */
|
|
.leaflet-control-help {
|
|
border: 1px solid #ccc;
|
|
box-shadow: 0 1px 5px rgba(0,0,0,0.2);
|
|
}
|
|
|
|
.leaflet-control-help i {
|
|
color: #007bff;
|
|
font-size: 16px;
|
|
}
|
|
|
|
/* Fullscreen Control */
|
|
.leaflet-control-fullscreen a {
|
|
background-color: white !important;
|
|
border-radius: 3px;
|
|
color: #333 !important;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.leaflet-control-fullscreen a:hover {
|
|
background-color: #007bff !important;
|
|
color: white !important;
|
|
}
|
|
|
|
/* Map Zoom Buttons in Header */
|
|
.map-zoom-controls {
|
|
display: inline-flex;
|
|
gap: 5px;
|
|
margin-left: 10px;
|
|
}
|
|
|
|
.map-zoom-controls .btn {
|
|
padding: 4px 8px;
|
|
font-size: 12px;
|
|
line-height: 1.2;
|
|
}
|
|
|
|
/* Enhanced Map Container */
|
|
#map {
|
|
border: 2px solid #e3f2fd;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
position: relative;
|
|
}
|
|
|
|
/* Map Loading Indicator */
|
|
.map-loading {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
background: rgba(255,255,255,0.9);
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
z-index: 10000;
|
|
display: none;
|
|
}
|
|
|
|
.map-loading.active {
|
|
display: block;
|
|
}
|
|
|
|
/* Responsive Map Controls */
|
|
@media (max-width: 768px) {
|
|
.leaflet-control-layers {
|
|
max-width: 200px;
|
|
}
|
|
|
|
.leaflet-control-coords {
|
|
font-size: 10px;
|
|
padding: 3px;
|
|
}
|
|
|
|
.map-zoom-controls {
|
|
display: none; /* Hide header zoom controls on mobile */
|
|
}
|
|
}
|
|
|
|
/* Map Tooltips */
|
|
.map-tooltip {
|
|
background: rgba(0,0,0,0.8);
|
|
color: white;
|
|
padding: 5px 10px;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
border: none;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
|
}
|
|
|
|
.map-tooltip:before {
|
|
border-top-color: rgba(0,0,0,0.8);
|
|
}
|
|
|
|
/* Item Detail Modal Styles */
|
|
.modal-xl {
|
|
max-width: 1140px;
|
|
}
|
|
|
|
.color-box {
|
|
border-radius: 3px;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
.popup-actions {
|
|
margin-top: 10px;
|
|
text-align: center;
|
|
}
|
|
|
|
.popup-actions .btn {
|
|
margin: 2px;
|
|
font-size: 11px;
|
|
}
|
|
|
|
.info-row {
|
|
margin-bottom: 5px;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.info-label {
|
|
font-weight: bold;
|
|
color: #666;
|
|
}
|
|
|
|
/* ==== Animasi kelap-kelip redaman ==== */
|
|
@keyframes blink {
|
|
0%, 50%, 100% { opacity: 1; }
|
|
25%, 75% { opacity: 0; }
|
|
}
|
|
|
|
.red-blink {
|
|
color: red;
|
|
animation: blink 1s infinite;
|
|
}
|
|
|
|
.green-stable {
|
|
color: green;
|
|
}
|
|
|
|
|
|
/* Enhanced table styling for detail modal */
|
|
.modal-body .table td {
|
|
border-top: none;
|
|
padding: 8px 12px;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
.modal-body .table tr:nth-child(even) {
|
|
background-color: #f8f9fa;
|
|
}
|
|
|
|
.modal-body .table td:first-child {
|
|
width: 35%;
|
|
font-weight: 500;
|
|
color: #495057;
|
|
}
|
|
|
|
.modal-body .card {
|
|
box-shadow: none;
|
|
border: 1px solid #dee2e6;
|
|
}
|
|
|
|
.modal-body .card-header {
|
|
border-bottom: 1px solid rgba(255,255,255,0.2);
|
|
}
|
|
|
|
/* Badge improvements */
|
|
.badge {
|
|
font-size: 0.85em;
|
|
padding: 0.4em 0.6em;
|
|
}
|
|
|
|
/* untuk animasi kabel*/
|
|
.leaflet-interactive.animated-route {
|
|
stroke-dasharray: 15, 10;
|
|
stroke-dashoffset: 1000;
|
|
animation: move-dash 20s linear infinite;
|
|
}
|
|
|
|
@keyframes move-dash {
|
|
to {
|
|
stroke-dashoffset: 0;
|
|
}
|
|
}
|
|
|
|
/* ONLINE (normal kuning) */
|
|
.status-online {
|
|
filter: none;
|
|
}
|
|
|
|
/* POWER FAIL (abu) */
|
|
.status-power {
|
|
filter: grayscale(100%) brightness(0.7);
|
|
}
|
|
|
|
/* LOS → MERAH + BLINK */
|
|
.status-los {
|
|
/* Mengubah kuning ke merah, menurunkan kecerahan untuk efek 'merah hati' */
|
|
filter: brightness(0.5) sepia(1) saturate(500%) hue-rotate(330deg) contrast(120%);
|
|
animation: blink 1s infinite;
|
|
}
|
|
|
|
/*
|
|
.status-los {
|
|
filter: brightness(0) saturate(100%) invert(19%) sepia(96%) saturate(7487%) hue-rotate(357deg) brightness(97%) contrast(119%);
|
|
animation: blink 1s infinite;
|
|
}
|
|
*/
|
|
|
|
|
|
@keyframes blink {
|
|
0% { opacity: 1; }
|
|
50% { opacity: 0.3; }
|
|
100% { opacity: 1; }
|
|
} |