update: spj
|
@ -10,7 +10,7 @@
|
|||
<!-- Navigation Content -->
|
||||
<div class="flex justify-between items-center px-8 relative pt-6">
|
||||
<!-- Home Button -->
|
||||
<a href="@Url.Action("Index", "Home")" class="flex flex-col items-center gap-1 px-4 py-2 transition-all duration-300 hover:scale-105 group">
|
||||
<a href="@Url.Action("Index", "SpjDriver")" class="flex flex-col items-center gap-1 px-4 py-2 transition-all duration-300 hover:scale-105 group">
|
||||
<div class="relative">
|
||||
<i class="w-6 h-6 text-gray-400 group-hover:text-orange-500 transition-colors duration-300" data-lucide="home"></i>
|
||||
<div class="absolute -bottom-0.5 left-1/2 transform -translate-x-1/2 w-0 h-0.5 bg-orange-500 group-hover:w-full transition-all duration-300"></div>
|
||||
|
@ -22,7 +22,7 @@
|
|||
|
||||
<!-- Profile Button -->
|
||||
|
||||
<a href="@Url.Action("Index", "History")" class="flex flex-col items-center gap-1 px-4 py-2 transition-all duration-300 hover:scale-105 group">
|
||||
<a href="@Url.Action("History", "SpjDriver")" class="flex flex-col items-center gap-1 px-4 py-2 transition-all duration-300 hover:scale-105 group">
|
||||
<div class="relative">
|
||||
<i class="w-6 h-6 text-gray-400 group-hover:text-orange-500 transition-colors duration-300" data-lucide="clipboard-check"></i>
|
||||
<div class="absolute -bottom-0.5 left-1/2 transform -translate-x-1/2 w-0 h-0.5 bg-orange-500 group-hover:w-full transition-all duration-300"></div>
|
||||
|
@ -34,7 +34,7 @@
|
|||
|
||||
<!-- Center Submit -->
|
||||
<div class="absolute -top-4 left-1/2 transform -translate-x-1/2">
|
||||
<a href="@Url.Action("Index", "Submit")" id="odoBtn" class="hover:cursor-pointer w-14 h-14 bg-gradient-to-br from-orange-500 via-orange-400 to-orange-600 rounded-full shadow-xl flex items-center justify-center transition-all duration-300 hover:scale-110 hover:rotate-6 border-4 border-white ring-2 ring-orange-200">
|
||||
<a href="@Url.Action("Submit", "SpjDriver")" id="odoBtn" class="hover:cursor-pointer w-14 h-14 bg-gradient-to-br from-orange-500 via-orange-400 to-orange-600 rounded-full shadow-xl flex items-center justify-center transition-all duration-300 hover:scale-110 hover:rotate-6 border-4 border-white ring-2 ring-orange-200">
|
||||
<i class="w-6 h-6 text-white" data-lucide="truck"></i>
|
||||
</a>
|
||||
|
||||
|
|
|
@ -0,0 +1,407 @@
|
|||
/* Modal animations and enhancements */
|
||||
#scan-modal {
|
||||
backdrop-filter: blur(8px);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
#scan-modal .bg-white {
|
||||
transform-origin: center center;
|
||||
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
}
|
||||
|
||||
/* Enhanced modal auto-hide animation */
|
||||
.modal-auto-hide {
|
||||
animation: modalAutoHide 0.4s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes modalAutoHide {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
80% {
|
||||
opacity: 1;
|
||||
transform: scale(1.02);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
|
||||
/* Success modal specific animations */
|
||||
.success-gradient-bg {
|
||||
background: linear-gradient(135deg, #10b981, #059669, #047857);
|
||||
animation: gradientShift 2s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes gradientShift {
|
||||
0%,
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Error modal specific animations */
|
||||
.error-gradient-bg {
|
||||
background: linear-gradient(135deg, #ef4444, #dc2626, #b91c1c);
|
||||
animation: gradientShift 2s ease-in-out;
|
||||
}
|
||||
|
||||
/* Enhanced pulse animation for icons */
|
||||
.icon-pulse {
|
||||
animation: iconPulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes iconPulse {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
/* Card shadow effects */
|
||||
.card-shadow-success {
|
||||
box-shadow: 0 10px 25px rgba(16, 185, 129, 0.2);
|
||||
}
|
||||
|
||||
.card-shadow-error {
|
||||
box-shadow: 0 10px 25px rgba(239, 68, 68, 0.2);
|
||||
}
|
||||
|
||||
/* Responsive modal improvements */
|
||||
@media (max-width: 640px) {
|
||||
#scan-modal .bg-white {
|
||||
margin: 16px;
|
||||
max-width: calc(100vw - 32px);
|
||||
}
|
||||
|
||||
#scan-modal .bg-white .space-y-4 > div {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.scanner-container {
|
||||
position: relative;
|
||||
background: #1a1a1a;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.scanner-overlay {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 250px;
|
||||
height: 120px;
|
||||
border: 2px dashed rgba(255, 255, 255, 0.7);
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
pointer-events: none;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.scanner-overlay::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
rgba(255, 255, 255, 0.2),
|
||||
transparent
|
||||
);
|
||||
animation: scan-line 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes scan-line {
|
||||
0% {
|
||||
left: -100%;
|
||||
}
|
||||
100% {
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
#video-preview {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.drawingBuffer {
|
||||
position: absolute !important;
|
||||
top: 0 !important;
|
||||
left: 0 !important;
|
||||
z-index: 5 !important;
|
||||
}
|
||||
|
||||
.btn-scanner {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-scanner:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
border-top: 2px solid white;
|
||||
border-radius: 50%;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.loading-spinner-small {
|
||||
border: 2px solid rgba(245, 158, 11, 0.3);
|
||||
border-top: 2px solid #f59e0b;
|
||||
border-radius: 50%;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.loading-spinner-modal {
|
||||
border: 3px solid rgba(59, 130, 246, 0.3);
|
||||
border-top: 3px solid #3b82f6;
|
||||
border-radius: 50%;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.scan-result-card {
|
||||
animation: slideInUp 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* OCR Processing Animation */
|
||||
.ocr-processing {
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
/* Receipt capture overlay */
|
||||
.receipt-overlay {
|
||||
position: absolute;
|
||||
top: 10%;
|
||||
left: 10%;
|
||||
right: 10%;
|
||||
bottom: 10%;
|
||||
border: 2px dashed rgba(245, 158, 11, 0.8);
|
||||
border-radius: 8px;
|
||||
pointer-events: none;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.receipt-overlay::before {
|
||||
content: "Arahkan ke teks struk";
|
||||
position: absolute;
|
||||
top: -30px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(245, 158, 11, 0.9);
|
||||
color: white;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Form transition effects */
|
||||
.form-section {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.form-section.disabled {
|
||||
opacity: 0.6;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.scanner-overlay {
|
||||
width: 200px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.scanner-container {
|
||||
height: 250px !important;
|
||||
}
|
||||
|
||||
.receipt-overlay::before {
|
||||
font-size: 11px;
|
||||
padding: 3px 6px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.scanner-container {
|
||||
background: #0a0a0a;
|
||||
}
|
||||
}
|
||||
|
||||
#scanner-container video {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
object-fit: cover !important;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
#scanner-container canvas {
|
||||
position: absolute !important;
|
||||
top: 0 !important;
|
||||
left: 0 !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
#scanner-container select,
|
||||
#scanner-container button {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Success feedback */
|
||||
.success-flash {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(34, 197, 94, 0.3);
|
||||
border-radius: 8px;
|
||||
z-index: 15;
|
||||
animation: flash 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes flash {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Input highlight when auto-filled */
|
||||
.auto-filled {
|
||||
background-color: rgba(34, 197, 94, 0.1) !important;
|
||||
border-color: rgb(34, 197, 94) !important;
|
||||
animation: highlight 1s ease-out;
|
||||
}
|
||||
|
||||
@keyframes highlight {
|
||||
0% {
|
||||
box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.3);
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 rgba(34, 197, 94, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Upload functionality styling */
|
||||
.upload-label {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.upload-label:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 8px rgba(59, 130, 246, 0.3);
|
||||
}
|
||||
|
||||
.upload-label:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Uploaded image display */
|
||||
#scanner-container img {
|
||||
border: 2px dashed rgba(245, 158, 11, 0.3);
|
||||
background-color: #f9fafb;
|
||||
}
|
||||
|
||||
/* Receipt format hints */
|
||||
.receipt-format-hint {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(245, 158, 11, 0.1),
|
||||
rgba(245, 158, 11, 0.05)
|
||||
);
|
||||
border-left: 4px solid #f59e0b;
|
||||
}
|
||||
|
||||
/* Enhanced OCR feedback */
|
||||
.ocr-success {
|
||||
animation: successPulse 0.6s ease-out;
|
||||
}
|
||||
|
||||
@keyframes successPulse {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.4);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.02);
|
||||
box-shadow: 0 0 0 10px rgba(34, 197, 94, 0);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 0 0 0 rgba(34, 197, 94, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Better mobile responsiveness for file upload */
|
||||
@media (max-width: 640px) {
|
||||
.upload-label {
|
||||
padding: 12px 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.upload-label i {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
@import "tailwindcss";
|
|
@ -0,0 +1,3 @@
|
|||
body {
|
||||
font-family: "Inter Tight", sans-serif;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="35" height="35" viewBox="0 0 35 35" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.67969 0.0136719C18.9654 0.167556 20.2506 9.91891 20.4727 14.002V28.8203H21.75V10.7715C21.7502 8.94744 23.2273 7.46998 25.0479 7.46973V21.875H25.4033L25.458 21.3301C25.6767 19.1466 27.558 17.7275 29.8213 17.7549C33.666 17.8098 35.002 20.4019 35.002 23.5957L35 23.5938V35H33.8145C32.6325 35 31.6738 34.0406 31.6738 32.8574V24.0576C31.6738 21.8743 30.6102 20.9727 28.9756 20.9453C26.6303 20.8632 25.0479 22.3922 25.0479 25.0938V28.8203H26.6416C27.9466 28.8203 29.0059 29.8812 29.0059 31.1875V32.0146H17.1719V14.002H17.1816C17.1788 13.975 17.173 13.9509 17.1719 13.9297C17.0045 10.8468 16.2597 3.65199 8.77148 2.96289C8.3974 4.9326 8.19092 9.16633 12.7021 11.0146C13.1377 8.74607 10.7711 5.62585 10.7695 5.57617C14.1321 7.59856 15.6921 10.4423 15.8711 14.0254H15.8789V14.2314C15.8851 14.4073 15.89 14.5853 15.8896 14.7646L15.8799 14.7627L15.9062 24.876L15.8789 32.1006V32.1016H12.584L12.5566 27.4121H12.2031L12.1758 27.7109C11.9042 30.5731 9.56065 32.3466 6.51172 32.3467C2.61714 32.3467 0.00195312 29.7284 0.00195312 25.04C0.00204911 20.3519 2.56255 17.543 6.51172 17.543C9.61701 17.5431 11.9589 19.3691 12.2305 22.6689L12.2578 22.9678H12.584V14.0488C2.79353 11.0936 6.28125 1.03095 6.29102 1L6.62402 0L7.67969 0.0136719ZM7.13672 20.7607C4.84958 20.7607 3.3243 22.26 3.29688 25.04C3.32421 27.8202 4.82218 29.1299 7.13672 29.1299C9.61518 29.1299 11.1953 27.5213 11.2227 24.8506C11.25 22.3697 9.61521 20.7608 7.13672 20.7607Z" fill="white"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 397 B |
After Width: | Height: | Size: 640 KiB |
|
@ -0,0 +1,4 @@
|
|||
// Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification
|
||||
// for details on configuring this project to bundle and minify static web assets.
|
||||
|
||||
// Write your JavaScript code.
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011-2021 Twitter, Inc.
|
||||
Copyright (c) 2011-2021 The Bootstrap Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,597 @@
|
|||
/*!
|
||||
* Bootstrap Reboot v5.3.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2024 The Bootstrap Authors
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
:root,
|
||||
[data-bs-theme=light] {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-black: #000;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-primary-text-emphasis: #052c65;
|
||||
--bs-secondary-text-emphasis: #2b2f32;
|
||||
--bs-success-text-emphasis: #0a3622;
|
||||
--bs-info-text-emphasis: #055160;
|
||||
--bs-warning-text-emphasis: #664d03;
|
||||
--bs-danger-text-emphasis: #58151c;
|
||||
--bs-light-text-emphasis: #495057;
|
||||
--bs-dark-text-emphasis: #495057;
|
||||
--bs-primary-bg-subtle: #cfe2ff;
|
||||
--bs-secondary-bg-subtle: #e2e3e5;
|
||||
--bs-success-bg-subtle: #d1e7dd;
|
||||
--bs-info-bg-subtle: #cff4fc;
|
||||
--bs-warning-bg-subtle: #fff3cd;
|
||||
--bs-danger-bg-subtle: #f8d7da;
|
||||
--bs-light-bg-subtle: #fcfcfd;
|
||||
--bs-dark-bg-subtle: #ced4da;
|
||||
--bs-primary-border-subtle: #9ec5fe;
|
||||
--bs-secondary-border-subtle: #c4c8cb;
|
||||
--bs-success-border-subtle: #a3cfbb;
|
||||
--bs-info-border-subtle: #9eeaf9;
|
||||
--bs-warning-border-subtle: #ffe69c;
|
||||
--bs-danger-border-subtle: #f1aeb5;
|
||||
--bs-light-border-subtle: #e9ecef;
|
||||
--bs-dark-border-subtle: #adb5bd;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg: #fff;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-emphasis-color: #000;
|
||||
--bs-emphasis-color-rgb: 0, 0, 0;
|
||||
--bs-secondary-color: rgba(33, 37, 41, 0.75);
|
||||
--bs-secondary-color-rgb: 33, 37, 41;
|
||||
--bs-secondary-bg: #e9ecef;
|
||||
--bs-secondary-bg-rgb: 233, 236, 239;
|
||||
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
|
||||
--bs-tertiary-color-rgb: 33, 37, 41;
|
||||
--bs-tertiary-bg: #f8f9fa;
|
||||
--bs-tertiary-bg-rgb: 248, 249, 250;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #0d6efd;
|
||||
--bs-link-color-rgb: 13, 110, 253;
|
||||
--bs-link-decoration: underline;
|
||||
--bs-link-hover-color: #0a58ca;
|
||||
--bs-link-hover-color-rgb: 10, 88, 202;
|
||||
--bs-code-color: #d63384;
|
||||
--bs-highlight-color: #212529;
|
||||
--bs-highlight-bg: #fff3cd;
|
||||
--bs-border-width: 1px;
|
||||
--bs-border-style: solid;
|
||||
--bs-border-color: #dee2e6;
|
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
|
||||
--bs-border-radius: 0.375rem;
|
||||
--bs-border-radius-sm: 0.25rem;
|
||||
--bs-border-radius-lg: 0.5rem;
|
||||
--bs-border-radius-xl: 1rem;
|
||||
--bs-border-radius-xxl: 2rem;
|
||||
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
|
||||
--bs-border-radius-pill: 50rem;
|
||||
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||||
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
|
||||
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
--bs-focus-ring-width: 0.25rem;
|
||||
--bs-focus-ring-opacity: 0.25;
|
||||
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
|
||||
--bs-form-valid-color: #198754;
|
||||
--bs-form-valid-border-color: #198754;
|
||||
--bs-form-invalid-color: #dc3545;
|
||||
--bs-form-invalid-border-color: #dc3545;
|
||||
}
|
||||
|
||||
[data-bs-theme=dark] {
|
||||
color-scheme: dark;
|
||||
--bs-body-color: #dee2e6;
|
||||
--bs-body-color-rgb: 222, 226, 230;
|
||||
--bs-body-bg: #212529;
|
||||
--bs-body-bg-rgb: 33, 37, 41;
|
||||
--bs-emphasis-color: #fff;
|
||||
--bs-emphasis-color-rgb: 255, 255, 255;
|
||||
--bs-secondary-color: rgba(222, 226, 230, 0.75);
|
||||
--bs-secondary-color-rgb: 222, 226, 230;
|
||||
--bs-secondary-bg: #343a40;
|
||||
--bs-secondary-bg-rgb: 52, 58, 64;
|
||||
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
|
||||
--bs-tertiary-color-rgb: 222, 226, 230;
|
||||
--bs-tertiary-bg: #2b3035;
|
||||
--bs-tertiary-bg-rgb: 43, 48, 53;
|
||||
--bs-primary-text-emphasis: #6ea8fe;
|
||||
--bs-secondary-text-emphasis: #a7acb1;
|
||||
--bs-success-text-emphasis: #75b798;
|
||||
--bs-info-text-emphasis: #6edff6;
|
||||
--bs-warning-text-emphasis: #ffda6a;
|
||||
--bs-danger-text-emphasis: #ea868f;
|
||||
--bs-light-text-emphasis: #f8f9fa;
|
||||
--bs-dark-text-emphasis: #dee2e6;
|
||||
--bs-primary-bg-subtle: #031633;
|
||||
--bs-secondary-bg-subtle: #161719;
|
||||
--bs-success-bg-subtle: #051b11;
|
||||
--bs-info-bg-subtle: #032830;
|
||||
--bs-warning-bg-subtle: #332701;
|
||||
--bs-danger-bg-subtle: #2c0b0e;
|
||||
--bs-light-bg-subtle: #343a40;
|
||||
--bs-dark-bg-subtle: #1a1d20;
|
||||
--bs-primary-border-subtle: #084298;
|
||||
--bs-secondary-border-subtle: #41464b;
|
||||
--bs-success-border-subtle: #0f5132;
|
||||
--bs-info-border-subtle: #087990;
|
||||
--bs-warning-border-subtle: #997404;
|
||||
--bs-danger-border-subtle: #842029;
|
||||
--bs-light-border-subtle: #495057;
|
||||
--bs-dark-border-subtle: #343a40;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #6ea8fe;
|
||||
--bs-link-hover-color: #8bb9fe;
|
||||
--bs-link-color-rgb: 110, 168, 254;
|
||||
--bs-link-hover-color-rgb: 139, 185, 254;
|
||||
--bs-code-color: #e685b5;
|
||||
--bs-highlight-color: #dee2e6;
|
||||
--bs-highlight-bg: #664d03;
|
||||
--bs-border-color: #495057;
|
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
|
||||
--bs-form-valid-color: #75b798;
|
||||
--bs-form-valid-border-color: #75b798;
|
||||
--bs-form-invalid-color: #ea868f;
|
||||
--bs-form-invalid-border-color: #ea868f;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
border: 0;
|
||||
border-top: var(--bs-border-width) solid;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
color: var(--bs-heading-color);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.1875em;
|
||||
color: var(--bs-highlight-color);
|
||||
background-color: var(--bs-highlight-bg);
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-code-color);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.1875rem 0.375rem;
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-body-bg);
|
||||
background-color: var(--bs-body-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: var(--bs-secondary-color);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: left;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
/* rtl:raw:
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
*/
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
|
@ -0,0 +1,594 @@
|
|||
/*!
|
||||
* Bootstrap Reboot v5.3.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2024 The Bootstrap Authors
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
:root,
|
||||
[data-bs-theme=light] {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-black: #000;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-primary-text-emphasis: #052c65;
|
||||
--bs-secondary-text-emphasis: #2b2f32;
|
||||
--bs-success-text-emphasis: #0a3622;
|
||||
--bs-info-text-emphasis: #055160;
|
||||
--bs-warning-text-emphasis: #664d03;
|
||||
--bs-danger-text-emphasis: #58151c;
|
||||
--bs-light-text-emphasis: #495057;
|
||||
--bs-dark-text-emphasis: #495057;
|
||||
--bs-primary-bg-subtle: #cfe2ff;
|
||||
--bs-secondary-bg-subtle: #e2e3e5;
|
||||
--bs-success-bg-subtle: #d1e7dd;
|
||||
--bs-info-bg-subtle: #cff4fc;
|
||||
--bs-warning-bg-subtle: #fff3cd;
|
||||
--bs-danger-bg-subtle: #f8d7da;
|
||||
--bs-light-bg-subtle: #fcfcfd;
|
||||
--bs-dark-bg-subtle: #ced4da;
|
||||
--bs-primary-border-subtle: #9ec5fe;
|
||||
--bs-secondary-border-subtle: #c4c8cb;
|
||||
--bs-success-border-subtle: #a3cfbb;
|
||||
--bs-info-border-subtle: #9eeaf9;
|
||||
--bs-warning-border-subtle: #ffe69c;
|
||||
--bs-danger-border-subtle: #f1aeb5;
|
||||
--bs-light-border-subtle: #e9ecef;
|
||||
--bs-dark-border-subtle: #adb5bd;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg: #fff;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-emphasis-color: #000;
|
||||
--bs-emphasis-color-rgb: 0, 0, 0;
|
||||
--bs-secondary-color: rgba(33, 37, 41, 0.75);
|
||||
--bs-secondary-color-rgb: 33, 37, 41;
|
||||
--bs-secondary-bg: #e9ecef;
|
||||
--bs-secondary-bg-rgb: 233, 236, 239;
|
||||
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
|
||||
--bs-tertiary-color-rgb: 33, 37, 41;
|
||||
--bs-tertiary-bg: #f8f9fa;
|
||||
--bs-tertiary-bg-rgb: 248, 249, 250;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #0d6efd;
|
||||
--bs-link-color-rgb: 13, 110, 253;
|
||||
--bs-link-decoration: underline;
|
||||
--bs-link-hover-color: #0a58ca;
|
||||
--bs-link-hover-color-rgb: 10, 88, 202;
|
||||
--bs-code-color: #d63384;
|
||||
--bs-highlight-color: #212529;
|
||||
--bs-highlight-bg: #fff3cd;
|
||||
--bs-border-width: 1px;
|
||||
--bs-border-style: solid;
|
||||
--bs-border-color: #dee2e6;
|
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
|
||||
--bs-border-radius: 0.375rem;
|
||||
--bs-border-radius-sm: 0.25rem;
|
||||
--bs-border-radius-lg: 0.5rem;
|
||||
--bs-border-radius-xl: 1rem;
|
||||
--bs-border-radius-xxl: 2rem;
|
||||
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
|
||||
--bs-border-radius-pill: 50rem;
|
||||
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||||
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
|
||||
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
--bs-focus-ring-width: 0.25rem;
|
||||
--bs-focus-ring-opacity: 0.25;
|
||||
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
|
||||
--bs-form-valid-color: #198754;
|
||||
--bs-form-valid-border-color: #198754;
|
||||
--bs-form-invalid-color: #dc3545;
|
||||
--bs-form-invalid-border-color: #dc3545;
|
||||
}
|
||||
|
||||
[data-bs-theme=dark] {
|
||||
color-scheme: dark;
|
||||
--bs-body-color: #dee2e6;
|
||||
--bs-body-color-rgb: 222, 226, 230;
|
||||
--bs-body-bg: #212529;
|
||||
--bs-body-bg-rgb: 33, 37, 41;
|
||||
--bs-emphasis-color: #fff;
|
||||
--bs-emphasis-color-rgb: 255, 255, 255;
|
||||
--bs-secondary-color: rgba(222, 226, 230, 0.75);
|
||||
--bs-secondary-color-rgb: 222, 226, 230;
|
||||
--bs-secondary-bg: #343a40;
|
||||
--bs-secondary-bg-rgb: 52, 58, 64;
|
||||
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
|
||||
--bs-tertiary-color-rgb: 222, 226, 230;
|
||||
--bs-tertiary-bg: #2b3035;
|
||||
--bs-tertiary-bg-rgb: 43, 48, 53;
|
||||
--bs-primary-text-emphasis: #6ea8fe;
|
||||
--bs-secondary-text-emphasis: #a7acb1;
|
||||
--bs-success-text-emphasis: #75b798;
|
||||
--bs-info-text-emphasis: #6edff6;
|
||||
--bs-warning-text-emphasis: #ffda6a;
|
||||
--bs-danger-text-emphasis: #ea868f;
|
||||
--bs-light-text-emphasis: #f8f9fa;
|
||||
--bs-dark-text-emphasis: #dee2e6;
|
||||
--bs-primary-bg-subtle: #031633;
|
||||
--bs-secondary-bg-subtle: #161719;
|
||||
--bs-success-bg-subtle: #051b11;
|
||||
--bs-info-bg-subtle: #032830;
|
||||
--bs-warning-bg-subtle: #332701;
|
||||
--bs-danger-bg-subtle: #2c0b0e;
|
||||
--bs-light-bg-subtle: #343a40;
|
||||
--bs-dark-bg-subtle: #1a1d20;
|
||||
--bs-primary-border-subtle: #084298;
|
||||
--bs-secondary-border-subtle: #41464b;
|
||||
--bs-success-border-subtle: #0f5132;
|
||||
--bs-info-border-subtle: #087990;
|
||||
--bs-warning-border-subtle: #997404;
|
||||
--bs-danger-border-subtle: #842029;
|
||||
--bs-light-border-subtle: #495057;
|
||||
--bs-dark-border-subtle: #343a40;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #6ea8fe;
|
||||
--bs-link-hover-color: #8bb9fe;
|
||||
--bs-link-color-rgb: 110, 168, 254;
|
||||
--bs-link-hover-color-rgb: 139, 185, 254;
|
||||
--bs-code-color: #e685b5;
|
||||
--bs-highlight-color: #dee2e6;
|
||||
--bs-highlight-bg: #664d03;
|
||||
--bs-border-color: #495057;
|
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
|
||||
--bs-form-valid-color: #75b798;
|
||||
--bs-form-valid-border-color: #75b798;
|
||||
--bs-form-invalid-color: #ea868f;
|
||||
--bs-form-invalid-border-color: #ea868f;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
border: 0;
|
||||
border-top: var(--bs-border-width) solid;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
color: var(--bs-heading-color);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.1875em;
|
||||
color: var(--bs-highlight-color);
|
||||
background-color: var(--bs-highlight-bg);
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-code-color);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.1875rem 0.375rem;
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-body-bg);
|
||||
background-color: var(--bs-body-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: var(--bs-secondary-color);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: right;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: right;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */
|
|
@ -0,0 +1,23 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) .NET Foundation and Contributors
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,435 @@
|
|||
/**
|
||||
* @license
|
||||
* Unobtrusive validation support library for jQuery and jQuery Validate
|
||||
* Copyright (c) .NET Foundation. All rights reserved.
|
||||
* Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
* @version v4.0.0
|
||||
*/
|
||||
|
||||
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
|
||||
/*global document: false, jQuery: false */
|
||||
|
||||
(function (factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define("jquery.validate.unobtrusive", ['jquery-validation'], factory);
|
||||
} else if (typeof module === 'object' && module.exports) {
|
||||
// CommonJS-like environments that support module.exports
|
||||
module.exports = factory(require('jquery-validation'));
|
||||
} else {
|
||||
// Browser global
|
||||
jQuery.validator.unobtrusive = factory(jQuery);
|
||||
}
|
||||
}(function ($) {
|
||||
var $jQval = $.validator,
|
||||
adapters,
|
||||
data_validation = "unobtrusiveValidation";
|
||||
|
||||
function setValidationValues(options, ruleName, value) {
|
||||
options.rules[ruleName] = value;
|
||||
if (options.message) {
|
||||
options.messages[ruleName] = options.message;
|
||||
}
|
||||
}
|
||||
|
||||
function splitAndTrim(value) {
|
||||
return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
|
||||
}
|
||||
|
||||
function escapeAttributeValue(value) {
|
||||
// As mentioned on http://api.jquery.com/category/selectors/
|
||||
return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
|
||||
}
|
||||
|
||||
function getModelPrefix(fieldName) {
|
||||
return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
|
||||
}
|
||||
|
||||
function appendModelPrefix(value, prefix) {
|
||||
if (value.indexOf("*.") === 0) {
|
||||
value = value.replace("*.", prefix);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function onError(error, inputElement) { // 'this' is the form element
|
||||
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
|
||||
replaceAttrValue = container.attr("data-valmsg-replace"),
|
||||
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
|
||||
|
||||
container.removeClass("field-validation-valid").addClass("field-validation-error");
|
||||
error.data("unobtrusiveContainer", container);
|
||||
|
||||
if (replace) {
|
||||
container.empty();
|
||||
error.removeClass("input-validation-error").appendTo(container);
|
||||
}
|
||||
else {
|
||||
error.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function onErrors(event, validator) { // 'this' is the form element
|
||||
var container = $(this).find("[data-valmsg-summary=true]"),
|
||||
list = container.find("ul");
|
||||
|
||||
if (list && list.length && validator.errorList.length) {
|
||||
list.empty();
|
||||
container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
|
||||
|
||||
$.each(validator.errorList, function () {
|
||||
$("<li />").html(this.message).appendTo(list);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function onSuccess(error) { // 'this' is the form element
|
||||
var container = error.data("unobtrusiveContainer");
|
||||
|
||||
if (container) {
|
||||
var replaceAttrValue = container.attr("data-valmsg-replace"),
|
||||
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
|
||||
|
||||
container.addClass("field-validation-valid").removeClass("field-validation-error");
|
||||
error.removeData("unobtrusiveContainer");
|
||||
|
||||
if (replace) {
|
||||
container.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onReset(event) { // 'this' is the form element
|
||||
var $form = $(this),
|
||||
key = '__jquery_unobtrusive_validation_form_reset';
|
||||
if ($form.data(key)) {
|
||||
return;
|
||||
}
|
||||
// Set a flag that indicates we're currently resetting the form.
|
||||
$form.data(key, true);
|
||||
try {
|
||||
$form.data("validator").resetForm();
|
||||
} finally {
|
||||
$form.removeData(key);
|
||||
}
|
||||
|
||||
$form.find(".validation-summary-errors")
|
||||
.addClass("validation-summary-valid")
|
||||
.removeClass("validation-summary-errors");
|
||||
$form.find(".field-validation-error")
|
||||
.addClass("field-validation-valid")
|
||||
.removeClass("field-validation-error")
|
||||
.removeData("unobtrusiveContainer")
|
||||
.find(">*") // If we were using valmsg-replace, get the underlying error
|
||||
.removeData("unobtrusiveContainer");
|
||||
}
|
||||
|
||||
function validationInfo(form) {
|
||||
var $form = $(form),
|
||||
result = $form.data(data_validation),
|
||||
onResetProxy = $.proxy(onReset, form),
|
||||
defaultOptions = $jQval.unobtrusive.options || {},
|
||||
execInContext = function (name, args) {
|
||||
var func = defaultOptions[name];
|
||||
func && $.isFunction(func) && func.apply(form, args);
|
||||
};
|
||||
|
||||
if (!result) {
|
||||
result = {
|
||||
options: { // options structure passed to jQuery Validate's validate() method
|
||||
errorClass: defaultOptions.errorClass || "input-validation-error",
|
||||
errorElement: defaultOptions.errorElement || "span",
|
||||
errorPlacement: function () {
|
||||
onError.apply(form, arguments);
|
||||
execInContext("errorPlacement", arguments);
|
||||
},
|
||||
invalidHandler: function () {
|
||||
onErrors.apply(form, arguments);
|
||||
execInContext("invalidHandler", arguments);
|
||||
},
|
||||
messages: {},
|
||||
rules: {},
|
||||
success: function () {
|
||||
onSuccess.apply(form, arguments);
|
||||
execInContext("success", arguments);
|
||||
}
|
||||
},
|
||||
attachValidation: function () {
|
||||
$form
|
||||
.off("reset." + data_validation, onResetProxy)
|
||||
.on("reset." + data_validation, onResetProxy)
|
||||
.validate(this.options);
|
||||
},
|
||||
validate: function () { // a validation function that is called by unobtrusive Ajax
|
||||
$form.validate();
|
||||
return $form.valid();
|
||||
}
|
||||
};
|
||||
$form.data(data_validation, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
$jQval.unobtrusive = {
|
||||
adapters: [],
|
||||
|
||||
parseElement: function (element, skipAttach) {
|
||||
/// <summary>
|
||||
/// Parses a single HTML element for unobtrusive validation attributes.
|
||||
/// </summary>
|
||||
/// <param name="element" domElement="true">The HTML element to be parsed.</param>
|
||||
/// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
|
||||
/// validation to the form. If parsing just this single element, you should specify true.
|
||||
/// If parsing several elements, you should specify false, and manually attach the validation
|
||||
/// to the form when you are finished. The default is false.</param>
|
||||
var $element = $(element),
|
||||
form = $element.parents("form")[0],
|
||||
valInfo, rules, messages;
|
||||
|
||||
if (!form) { // Cannot do client-side validation without a form
|
||||
return;
|
||||
}
|
||||
|
||||
valInfo = validationInfo(form);
|
||||
valInfo.options.rules[element.name] = rules = {};
|
||||
valInfo.options.messages[element.name] = messages = {};
|
||||
|
||||
$.each(this.adapters, function () {
|
||||
var prefix = "data-val-" + this.name,
|
||||
message = $element.attr(prefix),
|
||||
paramValues = {};
|
||||
|
||||
if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
|
||||
prefix += "-";
|
||||
|
||||
$.each(this.params, function () {
|
||||
paramValues[this] = $element.attr(prefix + this);
|
||||
});
|
||||
|
||||
this.adapt({
|
||||
element: element,
|
||||
form: form,
|
||||
message: message,
|
||||
params: paramValues,
|
||||
rules: rules,
|
||||
messages: messages
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.extend(rules, { "__dummy__": true });
|
||||
|
||||
if (!skipAttach) {
|
||||
valInfo.attachValidation();
|
||||
}
|
||||
},
|
||||
|
||||
parse: function (selector) {
|
||||
/// <summary>
|
||||
/// Parses all the HTML elements in the specified selector. It looks for input elements decorated
|
||||
/// with the [data-val=true] attribute value and enables validation according to the data-val-*
|
||||
/// attribute values.
|
||||
/// </summary>
|
||||
/// <param name="selector" type="String">Any valid jQuery selector.</param>
|
||||
|
||||
// $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
|
||||
// element with data-val=true
|
||||
var $selector = $(selector),
|
||||
$forms = $selector.parents()
|
||||
.addBack()
|
||||
.filter("form")
|
||||
.add($selector.find("form"))
|
||||
.has("[data-val=true]");
|
||||
|
||||
$selector.find("[data-val=true]").each(function () {
|
||||
$jQval.unobtrusive.parseElement(this, true);
|
||||
});
|
||||
|
||||
$forms.each(function () {
|
||||
var info = validationInfo(this);
|
||||
if (info) {
|
||||
info.attachValidation();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
adapters = $jQval.unobtrusive.adapters;
|
||||
|
||||
adapters.add = function (adapterName, params, fn) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
|
||||
/// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
|
||||
/// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
|
||||
/// mmmm is the parameter name).</param>
|
||||
/// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
|
||||
/// attributes into jQuery Validate rules and/or messages.</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
if (!fn) { // Called with no params, just a function
|
||||
fn = params;
|
||||
params = [];
|
||||
}
|
||||
this.push({ name: adapterName, params: params, adapt: fn });
|
||||
return this;
|
||||
};
|
||||
|
||||
adapters.addBool = function (adapterName, ruleName) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
|
||||
/// the jQuery Validate validation rule has no parameter values.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
|
||||
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
|
||||
/// of adapterName will be used instead.</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
return this.add(adapterName, function (options) {
|
||||
setValidationValues(options, ruleName || adapterName, true);
|
||||
});
|
||||
};
|
||||
|
||||
adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
|
||||
/// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
|
||||
/// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
|
||||
/// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
|
||||
/// have a minimum value.</param>
|
||||
/// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
|
||||
/// have a maximum value.</param>
|
||||
/// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
|
||||
/// have both a minimum and maximum value.</param>
|
||||
/// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
|
||||
/// contains the minimum value. The default is "min".</param>
|
||||
/// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
|
||||
/// contains the maximum value. The default is "max".</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
|
||||
var min = options.params.min,
|
||||
max = options.params.max;
|
||||
|
||||
if (min && max) {
|
||||
setValidationValues(options, minMaxRuleName, [min, max]);
|
||||
}
|
||||
else if (min) {
|
||||
setValidationValues(options, minRuleName, min);
|
||||
}
|
||||
else if (max) {
|
||||
setValidationValues(options, maxRuleName, max);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
adapters.addSingleVal = function (adapterName, attribute, ruleName) {
|
||||
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
|
||||
/// the jQuery Validate validation rule has a single value.</summary>
|
||||
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
|
||||
/// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
|
||||
/// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
|
||||
/// The default is "val".</param>
|
||||
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
|
||||
/// of adapterName will be used instead.</param>
|
||||
/// <returns type="jQuery.validator.unobtrusive.adapters" />
|
||||
return this.add(adapterName, [attribute || "val"], function (options) {
|
||||
setValidationValues(options, ruleName || adapterName, options.params[attribute]);
|
||||
});
|
||||
};
|
||||
|
||||
$jQval.addMethod("__dummy__", function (value, element, params) {
|
||||
return true;
|
||||
});
|
||||
|
||||
$jQval.addMethod("regex", function (value, element, params) {
|
||||
var match;
|
||||
if (this.optional(element)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
match = new RegExp(params).exec(value);
|
||||
return (match && (match.index === 0) && (match[0].length === value.length));
|
||||
});
|
||||
|
||||
$jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
|
||||
var match;
|
||||
if (nonalphamin) {
|
||||
match = value.match(/\W/g);
|
||||
match = match && match.length >= nonalphamin;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
|
||||
if ($jQval.methods.extension) {
|
||||
adapters.addSingleVal("accept", "mimtype");
|
||||
adapters.addSingleVal("extension", "extension");
|
||||
} else {
|
||||
// for backward compatibility, when the 'extension' validation method does not exist, such as with versions
|
||||
// of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
|
||||
// validating the extension, and ignore mime-type validations as they are not supported.
|
||||
adapters.addSingleVal("extension", "extension", "accept");
|
||||
}
|
||||
|
||||
adapters.addSingleVal("regex", "pattern");
|
||||
adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
|
||||
adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
|
||||
adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
|
||||
adapters.add("equalto", ["other"], function (options) {
|
||||
var prefix = getModelPrefix(options.element.name),
|
||||
other = options.params.other,
|
||||
fullOtherName = appendModelPrefix(other, prefix),
|
||||
element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
|
||||
|
||||
setValidationValues(options, "equalTo", element);
|
||||
});
|
||||
adapters.add("required", function (options) {
|
||||
// jQuery Validate equates "required" with "mandatory" for checkbox elements
|
||||
if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
|
||||
setValidationValues(options, "required", true);
|
||||
}
|
||||
});
|
||||
adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
|
||||
var value = {
|
||||
url: options.params.url,
|
||||
type: options.params.type || "GET",
|
||||
data: {}
|
||||
},
|
||||
prefix = getModelPrefix(options.element.name);
|
||||
|
||||
$.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
|
||||
var paramName = appendModelPrefix(fieldName, prefix);
|
||||
value.data[paramName] = function () {
|
||||
var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']");
|
||||
// For checkboxes and radio buttons, only pick up values from checked fields.
|
||||
if (field.is(":checkbox")) {
|
||||
return field.filter(":checked").val() || field.filter(":hidden").val() || '';
|
||||
}
|
||||
else if (field.is(":radio")) {
|
||||
return field.filter(":checked").val() || '';
|
||||
}
|
||||
return field.val();
|
||||
};
|
||||
});
|
||||
|
||||
setValidationValues(options, "remote", value);
|
||||
});
|
||||
adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
|
||||
if (options.params.min) {
|
||||
setValidationValues(options, "minlength", options.params.min);
|
||||
}
|
||||
if (options.params.nonalphamin) {
|
||||
setValidationValues(options, "nonalphamin", options.params.nonalphamin);
|
||||
}
|
||||
if (options.params.regex) {
|
||||
setValidationValues(options, "regex", options.params.regex);
|
||||
}
|
||||
});
|
||||
adapters.add("fileextensions", ["extensions"], function (options) {
|
||||
setValidationValues(options, "extension", options.params.extensions);
|
||||
});
|
||||
|
||||
$(function () {
|
||||
$jQval.unobtrusive.parse(document);
|
||||
});
|
||||
|
||||
return $jQval.unobtrusive;
|
||||
}));
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright Jörn Zaefferer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
Copyright OpenJS Foundation and other contributors, https://openjsf.org/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,9 @@
|
|||
<svg width="141" height="140" viewBox="0 0 141 140" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M30.2734 2.05371C74.7715 2.66045 79.8364 41.1082 80.7119 57.207V115.636H85.75V44.4717C85.7501 37.2786 91.5756 31.4543 98.7549 31.4541V88.252H100.156L100.372 86.1016C101.234 77.4926 108.649 71.897 117.573 72.0049C132.733 72.2208 138 82.441 138 95.0342L137.993 95.0273V140H133.319C128.659 140 124.88 136.218 124.88 131.553V96.8535C124.88 88.245 120.684 84.6919 114.239 84.584C104.992 84.2604 98.7549 90.2878 98.7549 100.939V115.636H105.039C110.184 115.636 114.36 119.816 114.36 124.966V128.229H67.7002V57.207H67.7256C67.7144 57.1018 67.7047 57.0069 67.7002 56.9238C67.0402 44.7688 64.1034 16.4004 34.5771 13.6836C33.1023 21.4501 32.2877 38.1421 50.0742 45.4297C51.7972 36.4559 42.4024 24.1019 42.457 23.9844C55.7154 31.9585 61.8678 43.1728 62.5732 57.3008H62.6016L62.6025 58.0049C62.6295 58.7335 62.6439 59.47 62.6426 60.2139L62.6084 60.207L62.71 100.083L62.6016 128.566V128.573H49.6104L49.502 110.081H48.1084L48 111.261C46.9291 122.546 37.6889 129.537 25.667 129.537C10.3113 129.537 4.86308e-05 119.216 0 100.73C0 82.2451 10.0957 71.169 25.667 71.1689C37.9112 71.1689 47.145 78.3686 48.2158 91.3799L48.3232 92.5596H49.6104V57.3945C11.007 45.7426 24.7593 6.0654 24.7979 5.94336L26.1113 2L30.2734 2.05371ZM28.1318 83.8564C19.1138 83.8566 13.0999 89.7688 12.9922 100.73C13.1 111.692 19.0061 116.856 28.1318 116.856C37.9042 116.856 44.1343 110.513 44.2422 99.9824C44.3499 90.2004 37.9043 83.8564 28.1318 83.8564Z" fill="#59C207"/>
|
||||
<path d="M18.7641 75C14.7641 77 6.4641 83.3 5.2641 92.5C4.2641 88.1667 5.5641 78.6 18.7641 75Z" fill="#C9FF9E"/>
|
||||
<path d="M96 34C93.9657 35.0286 89.7446 38.2686 89.1343 43C88.6257 40.7714 89.2869 35.8514 96 34Z" fill="#C9FF9E"/>
|
||||
<path d="M133.039 97.7773C133.366 93.3171 132.196 82.9628 124.903 77.227C129.139 78.5835 136.695 84.5928 133.039 97.7773Z" fill="#C9FF9E"/>
|
||||
<path d="M52.1485 12.9621C48.8059 9.9911 39.8738 4.62472 30.8862 6.92757C34.5382 4.38964 43.9033 2.04346 52.1485 12.9621Z" fill="#C9FF9E"/>
|
||||
<path d="M62.5 128.5H49.5C56.7 128.5 61.1667 120.167 62.5 116V128.5Z" fill="#C9FF9E" fill-opacity="0.3"/>
|
||||
<path d="M68 128.5H81C73.8 128.5 69.3333 120.167 68 116V128.5Z" fill="#C9FF9E" fill-opacity="0.3"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
"name": "eSPJ - Surat Perjalanan Dinas",
|
||||
"short_name": "eSPJ",
|
||||
"description": "Aplikasi pengelolaan Surat Perjalanan Dinas yang modern dan efisien",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#ffffff",
|
||||
"theme_color": "#fb923c",
|
||||
"orientation": "portrait-primary",
|
||||
"scope": "/",
|
||||
"lang": "id",
|
||||
"dir": "ltr",
|
||||
"icons": [
|
||||
{
|
||||
"src": "icon-72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "icon-96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "icon-128.png",
|
||||
"sizes": "128x128",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "icon-144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "icon-152.png",
|
||||
"sizes": "152x152",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
},
|
||||
{
|
||||
"src": "icon-384.png",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
}
|
||||
],
|
||||
"screenshots": [
|
||||
{
|
||||
"src": "screenshot-wide.png",
|
||||
"sizes": "1280x720",
|
||||
"type": "image/png",
|
||||
"form_factor": "wide"
|
||||
},
|
||||
{
|
||||
"src": "screenshot-narrow.png",
|
||||
"sizes": "360x640",
|
||||
"type": "image/png",
|
||||
"form_factor": "narrow"
|
||||
}
|
||||
],
|
||||
"shortcuts": [
|
||||
{
|
||||
"name": "Login",
|
||||
"short_name": "Login",
|
||||
"description": "Masuk ke aplikasi eSPJ",
|
||||
"url": "/login",
|
||||
"icons": [{ "src": "icon-96.png", "sizes": "96x96" }]
|
||||
},
|
||||
{
|
||||
"name": "Dashboard",
|
||||
"short_name": "Dashboard",
|
||||
"description": "Buka dashboard utama",
|
||||
"url": "/dashboard",
|
||||
"icons": [{ "src": "icon-96.png", "sizes": "96x96" }]
|
||||
}
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 73 KiB |
|
@ -0,0 +1,227 @@
|
|||
const CACHE_NAME = "espj-v1.0.0";
|
||||
const urlsToCache = [
|
||||
"/",
|
||||
"/login",
|
||||
"/driver/manifest.json",
|
||||
"/driver/icon-192.png",
|
||||
"/driver/icon-512.png",
|
||||
"https://unpkg.com/lucide@latest",
|
||||
"https://fonts.googleapis.com/css2?family=Inter+Tight:ital,wght@0,100..900;1,100..900&display=swap",
|
||||
];
|
||||
|
||||
// Install Service Worker
|
||||
self.addEventListener("install", (event) => {
|
||||
console.log("[SW] Installing...");
|
||||
event.waitUntil(
|
||||
caches
|
||||
.open(CACHE_NAME)
|
||||
.then((cache) => {
|
||||
console.log("[SW] Caching app shell");
|
||||
return cache.addAll(urlsToCache);
|
||||
})
|
||||
.then(() => {
|
||||
console.log("[SW] Skip waiting");
|
||||
return self.skipWaiting();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Activate Service Worker
|
||||
self.addEventListener("activate", (event) => {
|
||||
console.log("[SW] Activating...");
|
||||
event.waitUntil(
|
||||
caches
|
||||
.keys()
|
||||
.then((cacheNames) => {
|
||||
return Promise.all(
|
||||
cacheNames.map((cacheName) => {
|
||||
if (cacheName !== CACHE_NAME) {
|
||||
console.log("[SW] Deleting old cache:", cacheName);
|
||||
return caches.delete(cacheName);
|
||||
}
|
||||
})
|
||||
);
|
||||
})
|
||||
.then(() => {
|
||||
console.log("[SW] Claiming clients");
|
||||
return self.clients.claim();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Fetch Event - Cache Strategy: Network First with Cache Fallback
|
||||
self.addEventListener("fetch", (event) => {
|
||||
// Skip cross-origin requests
|
||||
if (!event.request.url.startsWith(self.location.origin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.respondWith(
|
||||
fetch(event.request)
|
||||
.then((response) => {
|
||||
// Check if we received a valid response
|
||||
if (!response || response.status !== 200 || response.type !== "basic") {
|
||||
return response;
|
||||
}
|
||||
|
||||
// Clone the response
|
||||
const responseToCache = response.clone();
|
||||
|
||||
caches.open(CACHE_NAME).then((cache) => {
|
||||
cache.put(event.request, responseToCache);
|
||||
});
|
||||
|
||||
return response;
|
||||
})
|
||||
.catch(() => {
|
||||
// Network failed, serve from cache
|
||||
return caches.match(event.request).then((response) => {
|
||||
if (response) {
|
||||
return response;
|
||||
}
|
||||
|
||||
// If no cache match, return offline page for navigation requests
|
||||
if (event.request.mode === "navigate") {
|
||||
return caches.match("/offline.html");
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Background Sync for offline actions
|
||||
self.addEventListener("sync", (event) => {
|
||||
console.log("[SW] Background sync:", event.tag);
|
||||
|
||||
if (event.tag === "background-sync-login") {
|
||||
event.waitUntil(handleBackgroundLogin());
|
||||
}
|
||||
});
|
||||
|
||||
// Push Notifications
|
||||
self.addEventListener("push", (event) => {
|
||||
console.log("[SW] Push received:", event.data?.text());
|
||||
|
||||
const options = {
|
||||
body: event.data?.text() || "Notifikasi dari eSPJ",
|
||||
icon: "/icon-192.png",
|
||||
badge: "/icon-72.png",
|
||||
vibrate: [100, 50, 100],
|
||||
data: {
|
||||
dateOfArrival: Date.now(),
|
||||
primaryKey: "1",
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
action: "explore",
|
||||
title: "Buka Aplikasi",
|
||||
icon: "/icon-96.png",
|
||||
},
|
||||
{
|
||||
action: "close",
|
||||
title: "Tutup",
|
||||
icon: "/icon-96.png",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
event.waitUntil(self.registration.showNotification("eSPJ", options));
|
||||
});
|
||||
|
||||
// Notification Click Handler
|
||||
self.addEventListener("notificationclick", (event) => {
|
||||
console.log("[SW] Notification click received.");
|
||||
|
||||
event.notification.close();
|
||||
|
||||
if (event.action === "explore") {
|
||||
event.waitUntil(clients.openWindow("/"));
|
||||
} else if (event.action === "close") {
|
||||
// Just close the notification
|
||||
return;
|
||||
} else {
|
||||
// Default action - open the app
|
||||
event.waitUntil(
|
||||
clients.matchAll().then((clientList) => {
|
||||
for (const client of clientList) {
|
||||
if (client.url === "/" && "focus" in client) {
|
||||
return client.focus();
|
||||
}
|
||||
}
|
||||
if (clients.openWindow) {
|
||||
return clients.openWindow("/");
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle background login sync
|
||||
async function handleBackgroundLogin() {
|
||||
try {
|
||||
// Implement your background login logic here
|
||||
console.log("[SW] Handling background login sync");
|
||||
|
||||
// Example: retry failed login attempts
|
||||
const failedLogins = await getFailedLogins();
|
||||
|
||||
for (const login of failedLogins) {
|
||||
try {
|
||||
await retryLogin(login);
|
||||
await removeFailedLogin(login.id);
|
||||
} catch (error) {
|
||||
console.error("[SW] Failed to retry login:", error);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[SW] Background sync failed:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions for background sync
|
||||
async function getFailedLogins() {
|
||||
// Implement logic to get failed login attempts from IndexedDB
|
||||
return [];
|
||||
}
|
||||
|
||||
async function retryLogin(loginData) {
|
||||
// Implement retry login logic
|
||||
const response = await fetch("/api/auth/login", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(loginData),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Login retry failed");
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async function removeFailedLogin(loginId) {
|
||||
// Implement logic to remove successful login from IndexedDB
|
||||
console.log("[SW] Removing failed login:", loginId);
|
||||
}
|
||||
|
||||
// Message handling between SW and main thread
|
||||
self.addEventListener("message", (event) => {
|
||||
console.log("[SW] Message received:", event.data);
|
||||
|
||||
if (event.data && event.data.type === "SKIP_WAITING") {
|
||||
self.skipWaiting();
|
||||
}
|
||||
|
||||
if (event.data && event.data.type === "GET_VERSION") {
|
||||
event.ports[0].postMessage({ version: CACHE_NAME });
|
||||
}
|
||||
});
|
||||
|
||||
// Update available notification
|
||||
self.addEventListener("message", (event) => {
|
||||
if (event.data.action === "skipWaiting") {
|
||||
self.skipWaiting();
|
||||
}
|
||||
});
|
|
@ -0,0 +1,16 @@
|
|||
<svg width="131" height="130" viewBox="0 0 131 130" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_910_490)">
|
||||
<path d="M62.1927 38.6598C62.6409 37.9513 63.7375 36.9328 63.9584 36.5997C67.5773 31.0814 75.6699 18.6362 63.7917 7.85047C60.6626 10.7583 54.9508 17.7779 60.2895 26.7418C63.9188 23.3848 63.8229 14.9334 63.8875 14.9081C67.2667 23.2267 65.8992 30.5057 60.9086 37.266L58.405 34.4678C41.4278 15.4774 61.9968 1.33266 62.0552 1.2926L63.8896 0L65.6678 1.37694C84.6859 16.11 73.8646 32.7134 69.072 40.0199L66.8394 43.2819L62.1907 38.6598H62.1927ZM53.9981 107.878C54.0106 103.964 53.3081 54.4156 8.82006 61.2665C9.1932 68.651 12.5766 89.6045 38.7136 92.7759C36.3913 84.9465 29.6642 75.308 22.7245 70.7217C34.2796 72.8915 44.0273 84.2317 46.2454 99.7492L42.5806 99.5826C1.66893e-06 97.6532 2.40149 58.5063 2.40775 58.3925L2.53491 55.8536L5.00311 55.3687C39.093 48.68 52.2011 69.0959 57.2376 86.4627C57.8255 76.5521 57.1751 66.5508 55.1217 57.5869C52.6368 46.7275 48.109 37.4558 41.2506 31.8932C36.8958 28.357 31.5091 26.3074 25.0114 26.3011C24.5777 31.9986 25.3074 45.7807 41.7947 49.5889C40.0999 44.37 37.3211 39.2523 31.9281 34.0587C40.1332 35.7794 48.6343 47.01 48.6052 57.0977L45.1822 56.7076C12.6099 52.9964 19.0618 22.6341 19.0806 22.5456L19.5621 20.1417L21.9699 19.9498C31.3695 19.2097 39.0826 21.8476 45.2552 26.8514C53.3227 33.3966 58.5592 43.9419 61.3526 56.1425C64.0793 68.0458 64.4921 81.5854 62.9516 94.4671C61.017 110.611 55.9514 125.852 48.4405 135.788C60.9232 134.736 72.7576 135.191 82.8681 136.224C75.1716 126.299 69.9872 110.847 68.0234 94.4671C66.4829 81.5875 66.8957 68.0458 69.6224 56.1425C72.4137 43.9419 77.6503 33.3966 85.7178 26.8514C91.8903 21.8476 99.6014 19.2097 109.003 19.9498L111.411 20.1417L111.892 22.5456C111.913 22.6341 118.363 52.9964 85.7907 56.7076L82.3636 57.0977C82.3344 47.01 90.8397 35.7794 99.0406 34.0587C93.6498 39.2502 90.8709 44.37 89.1741 49.5889C105.663 45.7807 106.393 31.9986 105.962 26.3011C99.4617 26.3074 94.0792 28.357 89.7223 31.8932C82.8639 37.4579 78.3361 46.7296 75.8512 57.5869C73.7958 66.574 73.1475 76.6048 73.7353 86.5428C78.7593 69.1634 91.8549 48.6737 125.999 55.3708L128.467 55.8558L128.592 58.3946C128.601 58.5084 131.002 97.6553 88.4236 99.5847L84.7526 99.7513C86.9706 84.2359 96.7204 72.8957 108.276 70.7238C101.336 75.3122 94.6066 84.9487 92.2843 92.778C118.421 89.6066 121.807 68.6531 122.182 61.2686C77.2229 54.346 76.9811 105.025 77.004 107.992C80.3123 121.038 85.8449 132.028 93.0911 137.532C105.999 139.501 114.231 142.002 114.231 142.002H16.8334C24.0858 139.632 31.4195 138 38.6406 136.927C45.5366 131.231 50.8065 120.515 53.9981 107.88V107.878Z" fill="white" fill-opacity="0.1"/>
|
||||
<mask id="mask0_910_490" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="2" y="0" width="127" height="143">
|
||||
<path d="M62.1927 38.6598C62.6409 37.9513 63.7375 36.9328 63.9584 36.5997C67.5773 31.0814 75.6699 18.6362 63.7917 7.85047C60.6626 10.7583 54.9508 17.7779 60.2895 26.7418C63.9188 23.3848 63.8229 14.9334 63.8875 14.9081C67.2667 23.2267 65.8992 30.5057 60.9086 37.266L58.405 34.4678C41.4278 15.4774 61.9968 1.33266 62.0552 1.2926L63.8896 0L65.6678 1.37694C84.6859 16.11 73.8646 32.7134 69.072 40.0199L66.8394 43.2819L62.1907 38.6598H62.1927ZM53.9981 107.878C54.0106 103.964 53.3081 54.4156 8.82006 61.2665C9.1932 68.651 12.5766 89.6045 38.7136 92.7759C36.3913 84.9465 29.6642 75.308 22.7245 70.7217C34.2796 72.8915 44.0273 84.2317 46.2454 99.7492L42.5806 99.5826C1.66893e-06 97.6532 2.40149 58.5063 2.40775 58.3925L2.53491 55.8536L5.00311 55.3687C39.093 48.68 52.2011 69.0959 57.2376 86.4627C57.8255 76.5521 57.1751 66.5508 55.1217 57.5869C52.6368 46.7275 48.109 37.4558 41.2506 31.8932C36.8958 28.357 31.5091 26.3074 25.0114 26.3011C24.5777 31.9986 25.3074 45.7807 41.7947 49.5889C40.0999 44.37 37.3211 39.2523 31.9281 34.0587C40.1332 35.7794 48.6343 47.01 48.6052 57.0977L45.1822 56.7076C12.6099 52.9964 19.0618 22.6341 19.0806 22.5456L19.5621 20.1417L21.9699 19.9498C31.3695 19.2097 39.0826 21.8476 45.2552 26.8514C53.3227 33.3966 58.5592 43.9419 61.3526 56.1425C64.0793 68.0458 64.4921 81.5854 62.9516 94.4671C61.017 110.611 55.9514 125.852 48.4405 135.788C60.9232 134.736 72.7576 135.191 82.8681 136.224C75.1716 126.299 69.9872 110.847 68.0234 94.4671C66.4829 81.5875 66.8957 68.0458 69.6224 56.1425C72.4137 43.9419 77.6503 33.3966 85.7178 26.8514C91.8903 21.8476 99.6014 19.2097 109.003 19.9498L111.411 20.1417L111.892 22.5456C111.913 22.6341 118.363 52.9964 85.7907 56.7076L82.3636 57.0977C82.3344 47.01 90.8397 35.7794 99.0406 34.0587C93.6498 39.2502 90.8709 44.37 89.1741 49.5889C105.663 45.7807 106.393 31.9986 105.962 26.3011C99.4617 26.3074 94.0792 28.357 89.7223 31.8932C82.8639 37.4579 78.3361 46.7296 75.8512 57.5869C73.7958 66.574 73.1475 76.6048 73.7353 86.5428C78.7593 69.1634 91.8549 48.6737 125.999 55.3708L128.467 55.8558L128.592 58.3946C128.601 58.5084 131.002 97.6553 88.4236 99.5847L84.7526 99.7513C86.9706 84.2359 96.7204 72.8957 108.276 70.7238C101.336 75.3122 94.6066 84.9487 92.2843 92.778C118.421 89.6066 121.807 68.6531 122.182 61.2686C77.2229 54.346 76.9811 105.025 77.004 107.992C80.3123 121.038 85.8449 132.028 93.0911 137.532C105.999 139.501 114.231 142.002 114.231 142.002H16.8334C24.0858 139.632 31.4195 138 38.6406 136.927C45.5366 131.231 50.8065 120.515 53.9981 107.88V107.878Z" fill="white"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_910_490)">
|
||||
<path d="M131 0H0V142H131V0Z" fill="white" fill-opacity="0.1"/>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_910_490">
|
||||
<rect width="131" height="130" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 5.4 KiB |