From d3b2df416c59d721ca04b29259eabdbdbd274aa7 Mon Sep 17 00:00:00 2001 From: marszayn Date: Mon, 4 Aug 2025 13:30:34 +0700 Subject: [PATCH] test --- Controllers/LoginController.cs | 0 .../SpjDriverController/ScanController.cs | 128 +++ SCANNER_README.md | 179 ++++ .../Transport/SpjDriver/Scan/Create.cshtml | 871 ++++++++++++++++++ .../Transport/SpjDriver/Scan/Detail.cshtml | 118 +++ .../Transport/SpjDriver/Scan/Index.cshtml | 552 +++++++++++ wwwroot/driver/css/scanner.css | 127 +++ wwwroot/driver/css/watch.css | 416 +++++++++ 8 files changed, 2391 insertions(+) delete mode 100644 Controllers/LoginController.cs create mode 100644 Controllers/SpjDriverController/ScanController.cs create mode 100644 SCANNER_README.md create mode 100644 Views/Admin/Transport/SpjDriver/Scan/Create.cshtml create mode 100644 Views/Admin/Transport/SpjDriver/Scan/Detail.cshtml create mode 100644 Views/Admin/Transport/SpjDriver/Scan/Index.cshtml create mode 100644 wwwroot/driver/css/scanner.css diff --git a/Controllers/LoginController.cs b/Controllers/LoginController.cs deleted file mode 100644 index e69de29..0000000 diff --git a/Controllers/SpjDriverController/ScanController.cs b/Controllers/SpjDriverController/ScanController.cs new file mode 100644 index 0000000..26856a0 --- /dev/null +++ b/Controllers/SpjDriverController/ScanController.cs @@ -0,0 +1,128 @@ +using Microsoft.AspNetCore.Mvc; + +namespace eSPJ.Controllers.SpjDriverController +{ + [Route("scan")] + public class ScanController : Controller + { + + [HttpGet("")] + public IActionResult Index() + { + return View("~/Views/Admin/Transport/SpjDriver/Scan/Index.cshtml"); + } + + [HttpGet("detail")] + public IActionResult Detail() + { + return View("~/Views/Admin/Transport/SpjDriver/Scan/Detail.cshtml"); + } + + [HttpGet("create")] + public IActionResult Create() + { + return View("~/Views/Admin/Transport/SpjDriver/Scan/Create.cshtml"); + } + + [HttpPost] + public async Task ProcessScan(string barcode) + { + try + { + // Validate barcode + if (string.IsNullOrEmpty(barcode)) + { + TempData["Error"] = "Kode barcode tidak boleh kosong."; + return RedirectToAction("Index"); + } + + // Basic validation for SPJ barcode format + if (barcode.Length < 5) + { + TempData["Error"] = "Format kode SPJ tidak valid. Minimal 5 karakter."; + return RedirectToAction("Index"); + } + + // Clean the barcode (remove any whitespace) + barcode = barcode.Trim(); + + // TODO: Add your SPJ validation logic here + // For example: + // - Check if SPJ exists in database + // - Validate SPJ format according to your business rules + // - Check SPJ status (active, completed, etc.) + + // Simulate SPJ lookup (replace with your actual database logic) + var spjData = await ValidateSpjCode(barcode); + + if (spjData == null) + { + TempData["Error"] = $"SPJ dengan kode '{barcode}' tidak ditemukan."; + return RedirectToAction("Index"); + } + + // Success - redirect to detail page or next step + TempData["Success"] = $"SPJ '{barcode}' berhasil ditemukan!"; + + // Redirect to appropriate page based on your workflow + // For example, redirect to detail page: + return RedirectToAction("Index", "Detail", new { spjCode = barcode }); + + // Or redirect to submission page: + // return RedirectToAction("Index", "Submit", new { spjCode = barcode }); + + } + catch (Exception) + { + // Log the error (add your logging here) + TempData["Error"] = "Terjadi kesalahan saat memproses scan. Silakan coba lagi."; + return RedirectToAction("Index"); + } + } + + private async Task ValidateSpjCode(string barcode) + { + // TODO: Implement your SPJ validation logic here + // This is just a sample implementation + + try + { + // Simulate database lookup + await Task.Delay(100); // Simulate async operation + + // Example validation rules: + // 1. Check format (e.g., starts with "SPJ" or specific pattern) + // 2. Check if exists in database + // 3. Check status + + // For demo purposes, accept codes that start with "SPJ" + if (barcode.ToUpper().StartsWith("SPJ")) + { + return new SpjData + { + Code = barcode, + Status = "Active", + Driver = "Sample Driver", + Vehicle = "Sample Vehicle" + }; + } + + // Return null if not found or invalid + return null; + } + catch + { + return null; + } + } + + // Sample model for SPJ data (replace with your actual model) + public class SpjData + { + public string Code { get; set; } = string.Empty; + public string Status { get; set; } = string.Empty; + public string Driver { get; set; } = string.Empty; + public string Vehicle { get; set; } = string.Empty; + } + } +} diff --git a/SCANNER_README.md b/SCANNER_README.md new file mode 100644 index 0000000..3369850 --- /dev/null +++ b/SCANNER_README.md @@ -0,0 +1,179 @@ +# SPJ Barcode Scanner + +Scanner barcode untuk aplikasi eSPJ yang menggunakan QuaggaJS library. + +## Fitur + +- Scanner barcode real-time menggunakan kamera device +- Mendukung berbagai format barcode (Code 128, Code 39, EAN, dll) +- Input manual sebagai alternatif +- Validasi format SPJ +- Responsive design untuk mobile dan desktop +- Sound feedback saat barcode terdeteksi + +## Format Barcode yang Didukung + +- Code 128 +- Code 39 +- Code 39 VIN +- EAN-13 +- EAN-8 +- Code 93 + +## Cara Penggunaan + +### Untuk User (Driver) + +1. **Akses Halaman Scanner** + + - Buka aplikasi eSPJ + - Navigasi ke halaman "Scan SPJ" + +2. **Menggunakan Camera Scanner** + + - Klik tombol "Mulai Scan" + - Izinkan akses kamera saat diminta browser + - Arahkan kamera ke barcode SPJ + - Scanner akan otomatis mendeteksi dan menampilkan hasil + - Klik "Konfirmasi" untuk melanjutkan atau "Scan Ulang" untuk mencoba lagi + +3. **Menggunakan Input Manual** + - Masukkan kode SPJ secara manual di field yang disediakan + - Klik tombol search untuk memproses + +### Browser Requirements + +- Chrome 21+ +- Firefox 17+ +- Safari 11+ +- Edge 12+ +- Opera 18+ + +### Permissions + +Scanner memerlukan akses kamera. Pastikan: + +- Akses kamera diizinkan pada browser +- Halaman diakses melalui HTTPS (untuk production) +- Device memiliki kamera yang berfungsi + +## Technical Implementation + +### Dependencies + +- **QuaggaJS**: Library untuk barcode scanning +- **Lucide Icons**: Untuk iconography +- **Tailwind CSS**: Untuk styling + +### File Structure + +``` +Views/Admin/Transport/SpjDriver/Scan/ +├── Index.cshtml # Main scanner page +Controllers/SpjDriverController/ +├── ScanController.cs # Backend logic +wwwroot/driver/css/ +├── scanner.css # Scanner-specific styles +``` + +### Key Components + +1. **BarcodeScanner Class** (JavaScript) + + - Handles camera initialization + - Manages QuaggaJS configuration + - Processes scan results + - Handles UI interactions + +2. **ScanController** (C#) + - Validates scanned codes + - Processes SPJ lookup + - Handles error responses + +### Configuration + +QuaggaJS configuration: + +```javascript +{ + inputStream: { + type: "LiveStream", + constraints: { + width: 320, + height: 240, + facingMode: "environment" // Use back camera + } + }, + decoder: { + readers: [ + "code_128_reader", + "code_39_reader", + "ean_reader", + // ... more readers + ] + } +} +``` + +## Customization + +### Menambah Format Barcode Baru + +Edit array `readers` di file Index.cshtml: + +```javascript +readers: ["code_128_reader", "your_new_reader_here"]; +``` + +### Mengubah Validasi SPJ + +Edit method `ValidateSpjCode` di ScanController.cs: + +```csharp +private async Task ValidateSpjCode(string barcode) +{ + // Your custom validation logic here +} +``` + +### Styling + +Edit file `scanner.css` untuk mengubah appearance scanner. + +## Troubleshooting + +### Camera Tidak Berfungsi + +1. Pastikan browser memiliki akses kamera +2. Cek apakah halaman diakses melalui HTTPS +3. Restart browser jika perlu +4. Cek device permissions + +### Barcode Tidak Terdeteksi + +1. Pastikan barcode dalam format yang didukung +2. Cek pencahayaan - barcode harus jelas terbaca +3. Jaga jarak optimal (15-30cm dari kamera) +4. Pastikan barcode tidak rusak atau blur + +### Performance Issues + +1. Tutup aplikasi lain yang menggunakan kamera +2. Gunakan browser yang up-to-date +3. Cek kecepatan internet untuk loading library + +## Development Notes + +- Library QuaggaJS dimuat dari CDN (dapat diunduh lokal jika perlu) +- Scanner otomatis stop setelah berhasil scan untuk menghemat resource +- Implementasi includes sound feedback dan haptic feedback +- Mobile-first responsive design + +## Future Enhancements + +- [ ] Support untuk QR Code +- [ ] Batch scanning multiple barcodes +- [ ] Offline scanning capability +- [ ] Advanced barcode validation +- [ ] Scan history +- [ ] Analytics dan reporting diff --git a/Views/Admin/Transport/SpjDriver/Scan/Create.cshtml b/Views/Admin/Transport/SpjDriver/Scan/Create.cshtml new file mode 100644 index 0000000..b62b584 --- /dev/null +++ b/Views/Admin/Transport/SpjDriver/Scan/Create.cshtml @@ -0,0 +1,871 @@ +@{ + Layout = "~/Views/Admin/Transport/SpjDriver/Shared/_Layout.cshtml"; + ViewData["Title"] = "Buat Barcode SPJ"; +} + + + +
+ +
+
+ + + +

Buat Barcode SPJ

+
+
+
+ + +
+ + @if (TempData["Success"] != null) + { +
+
+ + @TempData["Success"] +
+
+ } + + @if (TempData["Error"] != null) + { +
+
+ + @TempData["Error"] +
+
+ } + + +
+

Data SPJ

+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+
+ + + + + +
+
+ +
+

Petunjuk Penggunaan:

+
    +
  • Masukkan nomor SPJ (wajib diisi)
  • +
  • Data tambahan seperti nomor kendaraan dan tujuan bersifat opsional
  • +
  • QR Code akan berisi kombinasi semua data yang diisi
  • +
  • Gunakan fitur Download untuk menyimpan atau Print untuk mencetak
  • +
  • QR Code dapat di-scan menggunakan menu Scan SPJ
  • +
+
+
+
+
+ + + +
+ + + + + + + + + + + + + diff --git a/Views/Admin/Transport/SpjDriver/Scan/Detail.cshtml b/Views/Admin/Transport/SpjDriver/Scan/Detail.cshtml new file mode 100644 index 0000000..e21ad99 --- /dev/null +++ b/Views/Admin/Transport/SpjDriver/Scan/Detail.cshtml @@ -0,0 +1,118 @@ +@{ + Layout = "~/Views/Admin/Transport/SpjDriver/Shared/_Layout.cshtml"; + ViewData["Title"] = "Detail SPJ"; +} + +
+
+
+ + + +

Detail SPJ

+
+
+ +
+
+
+ +
+
+
+
+
+ Foto Driver +
+ +
+

Bonny Agung Putra

+

Driver

+ +
+
+ B 1234 XYZ +
+
+ JRC 005 +
+
+
+
+
+
+
+
+
+
+ +
+

Informasi SPJ

+
+ +
+
+
+ + Nomor SPJ +
+
SPJ/07-2025/PKM/000476
+
+ +
+
+ + Tujuan +
+
Taman Barito
+
+
+
+
+ +
+
+
+
+ +
+

Status Penjemputan

+
+ +
+
+
+
+ PENGANGKUTAN +
+

+ CV Tri Mitra Utama - Shell Radio Dalam +

+
+ +
+
+
+ SUDAH TIBA DI LOKASI +
+

+ CV Tri Berkah Sejahtera +

+
+ +
+
+
+ DIBATALKAN +
+

+ CV Tri Berkah Sejahtera +

+
+
+
+
+
+ + +
diff --git a/Views/Admin/Transport/SpjDriver/Scan/Index.cshtml b/Views/Admin/Transport/SpjDriver/Scan/Index.cshtml new file mode 100644 index 0000000..36e5112 --- /dev/null +++ b/Views/Admin/Transport/SpjDriver/Scan/Index.cshtml @@ -0,0 +1,552 @@ +@{ + Layout = "~/Views/Admin/Transport/SpjDriver/Shared/_Layout.cshtml"; + ViewData["Title"] = "Scan SPJ"; +} + +@section Styles { + + +} + + +
+
+
+ + + +

Scan SPJ

+
+
+
+ + +
+ + @if (TempData["Success"] != null) + { +
+
+ + @TempData["Success"] +
+
+ } + + @if (TempData["Error"] != null) + { +
+
+ + @TempData["Error"] +
+
+ } + + +
+
+ + + +
+
+
+

Memuat scanner...

+
+
+
+
+ + +
+ + + + + + + + + + + +
+
+ +
+

Tips Scanning:

+
    +
  • • Pastikan barcode dalam pencahayaan yang cukup
  • +
  • • Jaga jarak 15-30cm dari kamera
  • +
  • • Arahkan kamera secara tegak lurus ke barcode
  • +
  • • Pastikan barcode tidak buram atau rusak
  • +
  • Klik "Izinkan/Allow" saat browser meminta akses kamera
  • +
+
+
+
+
+ + +
+

Atau input manual:

+
+
+ + +
+
+
+ + + + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/wwwroot/driver/css/scanner.css b/wwwroot/driver/css/scanner.css new file mode 100644 index 0000000..e1ddbc2 --- /dev/null +++ b/wwwroot/driver/css/scanner.css @@ -0,0 +1,127 @@ +/* Scanner specific styles */ +.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 element styling */ +#video-preview { + width: 100%; + height: 100%; + object-fit: cover; + transform: scaleX(-1); /* Mirror effect for better UX */ +} + +/* Canvas overlay for QuaggaJS */ +.drawingBuffer { + position: absolute !important; + top: 0 !important; + left: 0 !important; + z-index: 5 !important; +} + +/* Button states */ +.btn-scanner { + transition: all 0.3s ease; +} + +.btn-scanner:active { + transform: scale(0.98); +} + +/* Loading animation improvements */ +.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; +} + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +/* Result card styling */ +.scan-result-card { + animation: slideInUp 0.3s ease-out; +} + +@keyframes slideInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Mobile optimizations */ +@media (max-width: 640px) { + .scanner-overlay { + width: 200px; + height: 100px; + } + + .scanner-container { + height: 250px !important; + } +} + +/* Dark mode support */ +@media (prefers-color-scheme: dark) { + .scanner-container { + background: #0a0a0a; + } +} diff --git a/wwwroot/driver/css/watch.css b/wwwroot/driver/css/watch.css index e49176d..b2721f6 100644 --- a/wwwroot/driver/css/watch.css +++ b/wwwroot/driver/css/watch.css @@ -14,6 +14,7 @@ --color-red-500: oklch(63.7% 0.237 25.331); --color-red-600: oklch(57.7% 0.245 27.325); --color-red-700: oklch(50.5% 0.213 27.518); + --color-red-800: oklch(44.4% 0.177 26.899); --color-orange-50: oklch(98% 0.016 73.684); --color-orange-100: oklch(95.4% 0.038 75.164); --color-orange-200: oklch(90.1% 0.076 70.697); @@ -23,25 +24,53 @@ --color-orange-600: oklch(64.6% 0.222 41.116); --color-orange-700: oklch(55.3% 0.195 38.402); --color-orange-800: oklch(47% 0.157 37.304); + --color-amber-50: oklch(98.7% 0.022 95.277); + --color-amber-200: oklch(92.4% 0.12 95.746); + --color-amber-400: oklch(82.8% 0.189 84.429); + --color-amber-600: oklch(66.6% 0.179 58.318); + --color-amber-700: oklch(55.5% 0.163 48.998); --color-yellow-50: oklch(98.7% 0.026 102.212); + --color-yellow-100: oklch(97.3% 0.071 103.193); --color-yellow-200: oklch(94.5% 0.129 101.54); --color-yellow-400: oklch(85.2% 0.199 91.936); --color-yellow-500: oklch(79.5% 0.184 86.047); --color-yellow-600: oklch(68.1% 0.162 75.834); + --color-yellow-800: oklch(47.6% 0.114 61.907); --color-green-50: oklch(98.2% 0.018 155.826); --color-green-100: oklch(96.2% 0.044 156.743); --color-green-200: oklch(92.5% 0.084 155.995); + --color-green-300: oklch(87.1% 0.15 154.449); --color-green-400: oklch(79.2% 0.209 151.711); --color-green-500: oklch(72.3% 0.219 149.579); --color-green-600: oklch(62.7% 0.194 149.214); --color-green-700: oklch(52.7% 0.154 150.069); + --color-green-800: oklch(44.8% 0.119 151.328); + --color-emerald-50: oklch(97.9% 0.021 166.113); + --color-emerald-200: oklch(90.5% 0.093 164.15); + --color-emerald-400: oklch(76.5% 0.177 163.223); + --color-emerald-600: oklch(59.6% 0.145 163.225); + --color-emerald-700: oklch(50.8% 0.118 165.612); + --color-teal-50: oklch(98.4% 0.014 180.72); + --color-blue-50: oklch(97% 0.014 254.604); --color-blue-100: oklch(93.2% 0.032 255.585); --color-blue-200: oklch(88.2% 0.059 254.128); --color-blue-500: oklch(62.3% 0.214 259.815); --color-blue-600: oklch(54.6% 0.245 262.881); --color-blue-700: oklch(48.8% 0.243 264.376); + --color-blue-800: oklch(42.4% 0.199 265.638); --color-indigo-50: oklch(96.2% 0.018 272.314); --color-purple-50: oklch(97.7% 0.014 308.299); + --color-purple-100: oklch(94.6% 0.033 307.174); + --color-purple-400: oklch(71.4% 0.203 305.504); + --color-purple-600: oklch(55.8% 0.288 302.321); + --color-rose-50: oklch(96.9% 0.015 12.422); + --color-slate-50: oklch(98.4% 0.003 247.858); + --color-slate-100: oklch(96.8% 0.007 247.896); + --color-slate-200: oklch(92.9% 0.013 255.508); + --color-slate-400: oklch(70.4% 0.04 256.788); + --color-slate-500: oklch(55.4% 0.046 257.417); + --color-slate-700: oklch(37.2% 0.044 257.287); + --color-slate-800: oklch(27.9% 0.041 260.031); --color-gray-50: oklch(98.5% 0.002 247.839); --color-gray-100: oklch(96.7% 0.003 264.542); --color-gray-200: oklch(92.8% 0.006 264.531); @@ -85,6 +114,7 @@ --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); --animate-spin: spin 1s linear infinite; --animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; + --blur-sm: 8px; --blur-lg: 16px; --default-transition-duration: 150ms; --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); @@ -265,6 +295,9 @@ .sticky { position: sticky; } + .inset-0 { + inset: calc(var(--spacing) * 0); + } .start-0 { inset-inline-start: calc(var(--spacing) * 0); } @@ -292,6 +325,9 @@ .top-0 { top: calc(var(--spacing) * 0); } + .top-1 { + top: calc(var(--spacing) * 1); + } .top-1\/2 { top: calc(1/2 * 100%); } @@ -319,6 +355,9 @@ .right-full { right: 100%; } + .-bottom-0 { + bottom: calc(var(--spacing) * -0); + } .-bottom-0\.5 { bottom: calc(var(--spacing) * -0.5); } @@ -343,6 +382,9 @@ .left-0 { left: calc(var(--spacing) * 0); } + .left-1 { + left: calc(var(--spacing) * 1); + } .left-1\/2 { left: calc(1/2 * 100%); } @@ -571,9 +613,15 @@ .me-auto { margin-inline-end: auto; } + .-mt-4 { + margin-top: calc(var(--spacing) * -4); + } .-mt-6 { margin-top: calc(var(--spacing) * -6); } + .-mt-8 { + margin-top: calc(var(--spacing) * -8); + } .-mt-10 { margin-top: calc(var(--spacing) * -10); } @@ -583,6 +631,9 @@ .mt-0 { margin-top: calc(var(--spacing) * 0); } + .mt-0\.5 { + margin-top: calc(var(--spacing) * 0.5); + } .mt-1 { margin-top: calc(var(--spacing) * 1); } @@ -688,6 +739,9 @@ .table-row { display: table-row; } + .h-0 { + height: calc(var(--spacing) * 0); + } .h-0\.5 { height: calc(var(--spacing) * 0.5); } @@ -724,6 +778,9 @@ .h-14 { height: calc(var(--spacing) * 14); } + .h-16 { + height: calc(var(--spacing) * 16); + } .h-20 { height: calc(var(--spacing) * 20); } @@ -796,6 +853,9 @@ .w-14 { width: calc(var(--spacing) * 14); } + .w-16 { + width: calc(var(--spacing) * 16); + } .w-20 { width: calc(var(--spacing) * 20); } @@ -868,14 +928,38 @@ .border-collapse { border-collapse: collapse; } + .-translate-x-1 { + --tw-translate-x: calc(var(--spacing) * -1); + translate: var(--tw-translate-x) var(--tw-translate-y); + } .-translate-x-1\/2 { --tw-translate-x: calc(calc(1/2 * 100%) * -1); translate: var(--tw-translate-x) var(--tw-translate-y); } + .-translate-x-12 { + --tw-translate-x: calc(var(--spacing) * -12); + translate: var(--tw-translate-x) var(--tw-translate-y); + } + .translate-x-16 { + --tw-translate-x: calc(var(--spacing) * 16); + translate: var(--tw-translate-x) var(--tw-translate-y); + } + .-translate-y-1 { + --tw-translate-y: calc(var(--spacing) * -1); + translate: var(--tw-translate-x) var(--tw-translate-y); + } .-translate-y-1\/2 { --tw-translate-y: calc(calc(1/2 * 100%) * -1); translate: var(--tw-translate-x) var(--tw-translate-y); } + .-translate-y-16 { + --tw-translate-y: calc(var(--spacing) * -16); + translate: var(--tw-translate-x) var(--tw-translate-y); + } + .translate-y-12 { + --tw-translate-y: calc(var(--spacing) * 12); + translate: var(--tw-translate-x) var(--tw-translate-y); + } .scale-110 { --tw-scale-x: 110%; --tw-scale-y: 110%; @@ -891,6 +975,9 @@ .animate-spin { animation: var(--animate-spin); } + .cursor-not-allowed { + cursor: not-allowed; + } .cursor-pointer { cursor: pointer; } @@ -900,6 +987,18 @@ .resize-none { resize: none; } + .list-inside { + list-style-position: inside; + } + .list-decimal { + list-style-type: decimal; + } + .list-disc { + list-style-type: disc; + } + .grid-cols-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } .grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } @@ -996,6 +1095,9 @@ margin-block-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse))); } } + .self-start { + align-self: flex-start; + } .truncate { overflow: hidden; text-overflow: ellipsis; @@ -1059,6 +1161,14 @@ border-top-left-radius: var(--radius-3xl); border-top-right-radius: var(--radius-3xl); } + .rounded-r-lg { + border-top-right-radius: var(--radius-lg); + border-bottom-right-radius: var(--radius-lg); + } + .rounded-r-xl { + border-top-right-radius: var(--radius-xl); + border-bottom-right-radius: var(--radius-xl); + } .rounded-b-2xl { border-bottom-right-radius: var(--radius-2xl); border-bottom-left-radius: var(--radius-2xl); @@ -1112,13 +1222,32 @@ border-bottom-style: var(--tw-border-style); border-bottom-width: 1px; } + .border-l-4 { + border-left-style: var(--tw-border-style); + border-left-width: 4px; + } .border-dashed { --tw-border-style: dashed; border-style: dashed; } + .border-amber-200 { + border-color: var(--color-amber-200); + } + .border-amber-400 { + border-color: var(--color-amber-400); + } .border-black { border-color: var(--color-black); } + .border-blue-200 { + border-color: var(--color-blue-200); + } + .border-emerald-200 { + border-color: var(--color-emerald-200); + } + .border-emerald-400 { + border-color: var(--color-emerald-400); + } .border-gray-50 { border-color: var(--color-gray-50); } @@ -1140,9 +1269,15 @@ .border-green-200 { border-color: var(--color-green-200); } + .border-green-300 { + border-color: var(--color-green-300); + } .border-green-400 { border-color: var(--color-green-400); } + .border-orange-200 { + border-color: var(--color-orange-200); + } .border-orange-300 { border-color: var(--color-orange-300); } @@ -1152,21 +1287,48 @@ .border-red-200 { border-color: var(--color-red-200); } + .border-red-400 { + border-color: var(--color-red-400); + } + .border-slate-200 { + border-color: var(--color-slate-200); + } + .border-slate-200\/50 { + border-color: color-mix(in srgb, oklch(92.9% 0.013 255.508) 50%, transparent); + @supports (color: color-mix(in lab, red, red)) { + border-color: color-mix(in oklab, var(--color-slate-200) 50%, transparent); + } + } .border-white { border-color: var(--color-white); } .border-yellow-200 { border-color: var(--color-yellow-200); } + .border-yellow-400 { + border-color: var(--color-yellow-400); + } + .border-t-transparent { + border-top-color: transparent; + } + .bg-amber-400 { + background-color: var(--color-amber-400); + } .bg-black { background-color: var(--color-black); } + .bg-blue-50 { + background-color: var(--color-blue-50); + } .bg-blue-100 { background-color: var(--color-blue-100); } .bg-blue-500 { background-color: var(--color-blue-500); } + .bg-emerald-400 { + background-color: var(--color-emerald-400); + } .bg-gray-50 { background-color: var(--color-gray-50); } @@ -1176,6 +1338,12 @@ .bg-gray-200 { background-color: var(--color-gray-200); } + .bg-gray-400 { + background-color: var(--color-gray-400); + } + .bg-gray-500 { + background-color: var(--color-gray-500); + } .bg-gray-800 { background-color: var(--color-gray-800); } @@ -1191,6 +1359,9 @@ .bg-green-500 { background-color: var(--color-green-500); } + .bg-green-600 { + background-color: var(--color-green-600); + } .bg-orange-50 { background-color: var(--color-orange-50); } @@ -1209,18 +1380,39 @@ .bg-red-100 { background-color: var(--color-red-100); } + .bg-red-400 { + background-color: var(--color-red-400); + } .bg-red-500 { background-color: var(--color-red-500); } + .bg-slate-100 { + background-color: var(--color-slate-100); + } .bg-transparent { background-color: transparent; } .bg-white { background-color: var(--color-white); } + .bg-white\/5 { + background-color: color-mix(in srgb, #fff 5%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-white) 5%, transparent); + } + } + .bg-white\/10 { + background-color: color-mix(in srgb, #fff 10%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-white) 10%, transparent); + } + } .bg-yellow-50 { background-color: var(--color-yellow-50); } + .bg-yellow-100 { + background-color: var(--color-yellow-100); + } .bg-yellow-400 { background-color: var(--color-yellow-400); } @@ -1235,10 +1427,30 @@ --tw-gradient-position: to right in oklab; background-image: linear-gradient(var(--tw-gradient-stops)); } + .from-amber-50 { + --tw-gradient-from: var(--color-amber-50); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .from-blue-50 { + --tw-gradient-from: var(--color-blue-50); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } .from-blue-100 { --tw-gradient-from: var(--color-blue-100); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } + .from-blue-600 { + --tw-gradient-from: var(--color-blue-600); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .from-emerald-50 { + --tw-gradient-from: var(--color-emerald-50); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .from-emerald-400 { + --tw-gradient-from: var(--color-emerald-400); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } .from-green-500 { --tw-gradient-from: var(--color-green-500); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); @@ -1247,6 +1459,10 @@ --tw-gradient-from: var(--color-indigo-50); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } + .from-orange-50 { + --tw-gradient-from: var(--color-orange-50); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } .from-orange-100 { --tw-gradient-from: var(--color-orange-100); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); @@ -1259,6 +1475,22 @@ --tw-gradient-from: var(--color-orange-500); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } + .from-purple-400 { + --tw-gradient-from: var(--color-purple-400); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .from-red-50 { + --tw-gradient-from: var(--color-red-50); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .from-slate-50 { + --tw-gradient-from: var(--color-slate-50); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .from-slate-100 { + --tw-gradient-from: var(--color-slate-100); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } .via-orange-400 { --tw-gradient-via: var(--color-orange-400); --tw-gradient-via-stops: var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); @@ -1273,10 +1505,26 @@ --tw-gradient-to: var(--color-blue-200); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } + .to-emerald-600 { + --tw-gradient-to: var(--color-emerald-600); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .to-green-50 { + --tw-gradient-to: var(--color-green-50); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } .to-green-400 { --tw-gradient-to: var(--color-green-400); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } + .to-indigo-50 { + --tw-gradient-to: var(--color-indigo-50); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .to-orange-50 { + --tw-gradient-to: var(--color-orange-50); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } .to-orange-200 { --tw-gradient-to: var(--color-orange-200); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); @@ -1297,6 +1545,46 @@ --tw-gradient-to: var(--color-purple-50); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } + .to-purple-100 { + --tw-gradient-to: var(--color-purple-100); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .to-purple-600 { + --tw-gradient-to: var(--color-purple-600); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .to-red-50 { + --tw-gradient-to: var(--color-red-50); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .to-red-100 { + --tw-gradient-to: var(--color-red-100); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .to-red-500 { + --tw-gradient-to: var(--color-red-500); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .to-rose-50 { + --tw-gradient-to: var(--color-rose-50); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .to-slate-50 { + --tw-gradient-to: var(--color-slate-50); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .to-slate-100 { + --tw-gradient-to: var(--color-slate-100); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .to-teal-50 { + --tw-gradient-to: var(--color-teal-50); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .to-yellow-50 { + --tw-gradient-to: var(--color-yellow-50); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } .object-contain { object-fit: contain; } @@ -1453,6 +1741,9 @@ .pb-6 { padding-bottom: calc(var(--spacing) * 6); } + .pb-8 { + padding-bottom: calc(var(--spacing) * 8); + } .pb-12 { padding-bottom: calc(var(--spacing) * 12); } @@ -1554,6 +1845,15 @@ .text-wrap { text-wrap: wrap; } + .break-all { + word-break: break-all; + } + .text-amber-600 { + color: var(--color-amber-600); + } + .text-amber-700 { + color: var(--color-amber-700); + } .text-black { color: var(--color-black); } @@ -1563,6 +1863,18 @@ .text-blue-700 { color: var(--color-blue-700); } + .text-blue-800 { + color: var(--color-blue-800); + } + .text-emerald-600 { + color: var(--color-emerald-600); + } + .text-emerald-700 { + color: var(--color-emerald-700); + } + .text-gray-300 { + color: var(--color-gray-300); + } .text-gray-400 { color: var(--color-gray-400); } @@ -1590,6 +1902,9 @@ .text-green-700 { color: var(--color-green-700); } + .text-green-800 { + color: var(--color-green-800); + } .text-orange-100 { color: var(--color-orange-100); } @@ -1608,12 +1923,33 @@ .text-red-600 { color: var(--color-red-600); } + .text-red-700 { + color: var(--color-red-700); + } + .text-red-800 { + color: var(--color-red-800); + } + .text-slate-400 { + color: var(--color-slate-400); + } + .text-slate-500 { + color: var(--color-slate-500); + } + .text-slate-700 { + color: var(--color-slate-700); + } + .text-slate-800 { + color: var(--color-slate-800); + } .text-white { color: var(--color-white); } .text-yellow-600 { color: var(--color-yellow-600); } + .text-yellow-800 { + color: var(--color-yellow-800); + } .capitalize { text-transform: capitalize; } @@ -1684,9 +2020,16 @@ --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } + .ring-4 { + --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } .ring-orange-200 { --tw-ring-color: var(--color-orange-200); } + .ring-white { + --tw-ring-color: var(--color-white); + } .outline { outline-style: var(--tw-outline-style); outline-width: 1px; @@ -1720,6 +2063,11 @@ -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); } + .backdrop-blur-sm { + --tw-backdrop-blur: blur(var(--blur-sm)); + -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + } .backdrop-filter { -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); @@ -1841,6 +2189,13 @@ } } } + .hover\:bg-blue-600 { + &:hover { + @media (hover: hover) { + background-color: var(--color-blue-600); + } + } + } .hover\:bg-gray-50 { &:hover { @media (hover: hover) { @@ -1862,6 +2217,27 @@ } } } + .hover\:bg-gray-600 { + &:hover { + @media (hover: hover) { + background-color: var(--color-gray-600); + } + } + } + .hover\:bg-green-600 { + &:hover { + @media (hover: hover) { + background-color: var(--color-green-600); + } + } + } + .hover\:bg-green-700 { + &:hover { + @media (hover: hover) { + background-color: var(--color-green-700); + } + } + } .hover\:bg-orange-600 { &:hover { @media (hover: hover) { @@ -1893,6 +2269,16 @@ } } } + .hover\:bg-white\/20 { + &:hover { + @media (hover: hover) { + background-color: color-mix(in srgb, #fff 20%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-white) 20%, transparent); + } + } + } + } .hover\:from-orange-600 { &:hover { @media (hover: hover) { @@ -1931,6 +2317,13 @@ } } } + .hover\:text-orange-700 { + &:hover { + @media (hover: hover) { + color: var(--color-orange-700); + } + } + } .hover\:text-orange-800 { &:hover { @media (hover: hover) { @@ -1938,6 +2331,13 @@ } } } + .hover\:no-underline { + &:hover { + @media (hover: hover) { + text-decoration-line: none; + } + } + } .hover\:shadow-lg { &:hover { @media (hover: hover) { @@ -1956,6 +2356,11 @@ border-color: var(--color-red-500); } } + .focus\:border-transparent { + &:focus { + border-color: transparent; + } + } .focus\:ring-2 { &:focus { --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); @@ -1972,11 +2377,22 @@ --tw-ring-color: var(--color-orange-400); } } + .focus\:ring-orange-500 { + &:focus { + --tw-ring-color: var(--color-orange-500); + } + } .focus\:ring-red-200 { &:focus { --tw-ring-color: var(--color-red-200); } } + .focus\:outline-none { + &:focus { + --tw-outline-style: none; + outline-style: none; + } + } } @property --tw-translate-x { syntax: "*";