Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b5839ebd5 | ||
|
|
e2742a7a60 | ||
|
|
ae22adee40 | ||
|
|
ee02bd4f9a | ||
|
|
310d8adc8d | ||
|
|
ccbcd99053 | ||
|
|
52e60b99dd | ||
|
|
e19321a2b7 | ||
|
|
d1275b5b65 | ||
|
|
12162fd6f7 | ||
|
|
9ab8d41adf | ||
|
|
6f07fc05ac | ||
|
|
cbcc7da33d | ||
|
|
d1282364e7 | ||
|
|
254fe19bb6 | ||
|
|
99acc43ff0 |
@@ -136,7 +136,11 @@ jobs:
|
|||||||
rm -rf gen/android
|
rm -rf gen/android
|
||||||
bun tauri android init
|
bun tauri android init
|
||||||
|
|
||||||
- name: Patch AndroidManifest (CAMERA permission)
|
- name: Generate Android launcher icons from SVG logo
|
||||||
|
working-directory: apps/tauri
|
||||||
|
run: bun run scripts/generate-icons.js
|
||||||
|
|
||||||
|
- name: Patch AndroidManifest (CAMERA permission + deep link)
|
||||||
working-directory: apps/tauri
|
working-directory: apps/tauri
|
||||||
run: bash scripts/patch-android-manifest.sh
|
run: bash scripts/patch-android-manifest.sh
|
||||||
|
|
||||||
|
|||||||
+27
-10
@@ -64,23 +64,40 @@ function decodeGoogleIdToken(idToken: string): GoogleIdPayload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render a page for the Android system browser that redirects back to the
|
* Render a page for the Android system browser that uses Chrome's native
|
||||||
* Tauri app via a custom scheme (zeavisedu://). The app's AndroidManifest
|
* `intent://` protocol to open the Tauri app with the session URL.
|
||||||
* must register an intent filter for this scheme.
|
* Falls back to a clickable button if the intent is blocked.
|
||||||
*/
|
*/
|
||||||
function renderTauriDeepLinkPage(targetUrl: string): Response {
|
function renderTauriDeepLinkPage(targetUrl: string): Response {
|
||||||
// Rewrite https://... to zeavisedu://... for the custom scheme
|
// Extract the path + query from the full URL for the intent
|
||||||
const deepLink = targetUrl.replace(/^https?:\/\//, 'zeavisedu://');
|
let pathAndQuery = '/login';
|
||||||
|
try {
|
||||||
|
const u = new URL(targetUrl);
|
||||||
|
pathAndQuery = u.pathname + u.search + u.hash;
|
||||||
|
} catch { /* use default */ }
|
||||||
|
|
||||||
|
const displayUrl = targetUrl.replace(/"/g, '"');
|
||||||
|
const escapedPath = pathAndQuery.replace(/"/g, '"');
|
||||||
|
// intent:// scheme: Chrome on Android opens the target app by package name
|
||||||
|
// browser_fallback_url: shown if the app isn't installed
|
||||||
|
// Use intent://login/... to produce data URI zeavisedu://login/login?token=xxx
|
||||||
|
// which new URL() can parse (single-slash non-hierarchical URLs break WebView)
|
||||||
|
const intentUrl = `intent://login${escapedPath}#Intent;scheme=zeavisedu;package=com.zeavis.edu;S.browser_fallback_url=${encodeURIComponent(targetUrl)};end`;
|
||||||
|
|
||||||
const html = `<!DOCTYPE html>
|
const html = `<!DOCTYPE html>
|
||||||
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title>Kembali ke ZeaVis Edu</title></head>
|
<title>Kembali ke ZeaVis Edu</title></head>
|
||||||
<body style="font-family:sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#f0fdf4">
|
<body style="font-family:sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#f0fdf4">
|
||||||
<div style="text-align:center;padding:2rem">
|
<div style="text-align:center;padding:2rem;max-width:360px">
|
||||||
<p style="color:#166534;font-size:1.1rem;margin-bottom:1.5rem">Login berhasil!<br>Kembali ke aplikasi...</p>
|
<p style="color:#166534;font-size:1.1rem;margin-bottom:1.5rem">Login Google berhasil!<br>Kembali ke aplikasi...</p>
|
||||||
<a href="${deepLink.replace(/"/g, '"')}" style="display:inline-block;background:#16a34a;color:white;padding:0.75rem 2rem;border-radius:0.5rem;text-decoration:none;font-weight:600;font-size:1rem">Buka ZeaVis Edu</a>
|
<a href="${intentUrl.replace(/"/g, '"')}" id="open-app" style="display:inline-block;background:#16a34a;color:white;padding:0.75rem 2rem;border-radius:0.5rem;text-decoration:none;font-weight:600;font-size:1rem;margin-bottom:1rem">Buka ZeaVis Edu</a>
|
||||||
<p style="color:#6b7280;font-size:0.8rem;margin-top:1rem">Jika tombol tidak berfungsi, salin URL ini:<br><code style="word-break:break-all;font-size:0.75rem">${deepLink.replace(/</g, '<')}</code></p>
|
<p style="color:#6b7280;font-size:0.8rem">Jika tombol di atas tidak berfungsi, salin dan buka URL ini di aplikasi ZeaVis Edu:</p>
|
||||||
|
<code style="display:block;word-break:break-all;font-size:0.7rem;color:#4b5563;background:#e5e7eb;padding:0.5rem;border-radius:0.25rem;margin-top:0.5rem">${displayUrl.replace(/</g, '<').replace(/>/g, '>')}</code>
|
||||||
</div>
|
</div>
|
||||||
<script>window.location.href=${JSON.stringify(deepLink)};</script>
|
<script>
|
||||||
|
// Auto-open the intent
|
||||||
|
window.location.href = ${JSON.stringify(intentUrl)};
|
||||||
|
</script>
|
||||||
</body></html>`;
|
</body></html>`;
|
||||||
return new Response(html, {
|
return new Response(html, {
|
||||||
status: 200,
|
status: 200,
|
||||||
|
|||||||
@@ -12,5 +12,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "^2"
|
"@tauri-apps/cli": "^2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"sharp": "0.35.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Generate Android launcher icons from the ZeaVis Edu logo SVG.
|
||||||
|
* Produces PNGs at all required densities and replaces Tauri's default icons.
|
||||||
|
*
|
||||||
|
* Usage: node scripts/generate-icons.js
|
||||||
|
* Requires: bun add sharp (already in devDependencies)
|
||||||
|
*/
|
||||||
|
|
||||||
|
const sharp = require('sharp');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const LOGO = path.resolve(__dirname, '../../../.github/assets/zeavis-logo.svg');
|
||||||
|
const RES = path.resolve(__dirname, '../gen/android/app/src/main/res');
|
||||||
|
|
||||||
|
// Android density buckets: [folder, size]
|
||||||
|
const DENSITIES = [
|
||||||
|
['mipmap-mdpi', 48],
|
||||||
|
['mipmap-hdpi', 72],
|
||||||
|
['mipmap-xhdpi', 96],
|
||||||
|
['mipmap-xxhdpi', 144],
|
||||||
|
['mipmap-xxxhdpi', 192],
|
||||||
|
];
|
||||||
|
|
||||||
|
async function generate() {
|
||||||
|
if (!fs.existsSync(LOGO)) {
|
||||||
|
console.error(`ERROR: Logo not found at ${LOGO}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Generating icons from ${LOGO}...`);
|
||||||
|
|
||||||
|
for (const [folder, size] of DENSITIES) {
|
||||||
|
const dir = path.join(RES, folder);
|
||||||
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
||||||
|
|
||||||
|
const png = await sharp(LOGO)
|
||||||
|
.resize(size, size, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } })
|
||||||
|
.png()
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
// Write both legacy and adaptive icon names
|
||||||
|
for (const name of ['ic_launcher.png', 'ic_launcher_foreground.png', 'ic_launcher_round.png']) {
|
||||||
|
fs.writeFileSync(path.join(dir, name), png);
|
||||||
|
}
|
||||||
|
console.log(` ${folder}: ${size}x${size} OK`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also write the legacy icon to drawable for completeness
|
||||||
|
const drawableDir = path.join(RES, 'drawable');
|
||||||
|
if (!fs.existsSync(drawableDir)) fs.mkdirSync(drawableDir, { recursive: true });
|
||||||
|
const refPng = await sharp(LOGO)
|
||||||
|
.resize(144, 144, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } })
|
||||||
|
.png()
|
||||||
|
.toBuffer();
|
||||||
|
fs.writeFileSync(path.join(drawableDir, 'ic_launcher.png'), refPng);
|
||||||
|
|
||||||
|
console.log('Done. Android launcher icons generated.');
|
||||||
|
}
|
||||||
|
|
||||||
|
generate().catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 103 KiB |
@@ -37,12 +37,12 @@ export function AuthForm({ mode, isSubmitting, error, googleOAuthEnabled, onSubm
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="mx-auto w-full max-w-md">
|
<Card className="mx-auto w-full max-w-md bg-transparent border-none shadow-none">
|
||||||
<CardHeader>
|
<CardHeader className="text-center space-y-2">
|
||||||
<CardTitle>{mode === 'login' ? 'Masuk ke ZeaVis Edu' : 'Buat akun ZeaVis Edu'}</CardTitle>
|
<CardTitle className="text-2xl font-bold text-emerald-900">{mode === 'login' ? 'Masuk Akun ZeaVis Edu' : 'Buat akun ZeaVis Edu'}</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription className="text-sm text-emerald-800/80">
|
||||||
{mode === 'login'
|
{mode === 'login'
|
||||||
? 'Masuk untuk melihat riwayat diagnosis daun jagung Anda.'
|
? 'Masuk untuk menyimpan diagnosis dan mengikuti review pakar.'
|
||||||
: 'Daftar untuk menyimpan diagnosis dan mengikuti review pakar.'}
|
: 'Daftar untuk menyimpan diagnosis dan mengikuti review pakar.'}
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|||||||
@@ -35,20 +35,25 @@ export async function setupDeepLinkHandler(): Promise<void> {
|
|||||||
const { onOpenUrl } = await import('@tauri-apps/plugin-deep-link');
|
const { onOpenUrl } = await import('@tauri-apps/plugin-deep-link');
|
||||||
onOpenUrl((urls) => {
|
onOpenUrl((urls) => {
|
||||||
for (const url of urls) {
|
for (const url of urls) {
|
||||||
// url looks like: zeavisedu://zeavisedu.asepharyana.my.id/login?token=xxx
|
// url looks like: zeavisedu://login/login?token=xxx
|
||||||
// Extract path + query after the host
|
// Extract path + query after the host
|
||||||
try {
|
try {
|
||||||
const u = new URL(url);
|
const u = new URL(url);
|
||||||
const target = u.pathname + u.search + u.hash;
|
const target = u.pathname + u.search + u.hash;
|
||||||
if (target && target !== '/') {
|
if (target && target !== '/') {
|
||||||
window.location.href = target;
|
window.location.href = target;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch { /* try fallback below */ }
|
||||||
// If URL parsing fails, try to extract everything after the scheme
|
|
||||||
const match = url.match(/^[^:]+:\/\/(?:[^/]+)?(\/.*)?$/);
|
// Fallback: extract everything after scheme, handling both // and /
|
||||||
if (match?.[1]) {
|
let match = url.match(/^[^:]+:\/\/(?:[^/]+)?(\/.*)?$/);
|
||||||
window.location.href = match[1];
|
if (!match) {
|
||||||
}
|
// Also handle single-slash non-hierarchical URLs (e.g. zeavisedu:/path)
|
||||||
|
match = url.match(/^[^:]+:\/(\/.*)?$/);
|
||||||
|
}
|
||||||
|
if (match?.[1]) {
|
||||||
|
window.location.href = match[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -54,12 +54,12 @@ export function CatalogPage() {
|
|||||||
<div className="space-y-6 max-w-5xl mx-auto pb-10">
|
<div className="space-y-6 max-w-5xl mx-auto pb-10">
|
||||||
{/* Page Title */}
|
{/* Page Title */}
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl md:text-3xl font-extrabold text-[#214B11]">
|
<h1 className="text-2xl font-bold text-emerald-800">
|
||||||
Pustaka Penyakit
|
Pustaka Penyakit
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mt-1 text-muted-foreground text-sm md:text-base">
|
<p className="text-gray-500 mt-1 text-md">
|
||||||
Referensi lengkap penyakit dan kondisi daun jagung yang dapat
|
Referensi lengkap penyakit dan kondisi daun jagung yang dapat
|
||||||
dideteksi oleh sistem AI ZeaVis Edu.
|
dideteksi oleh sistem AI ZeaVis Edu
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { useUiStore } from "@/store/ui-store";
|
import { useUiStore } from "@/store/ui-store";
|
||||||
import { apiClient } from "@/lib/api-client";
|
import { apiClient } from "@/lib/api-client";
|
||||||
import bg from "@/assets/images/dashboard-bg.webp";
|
|
||||||
|
|
||||||
export function DashboardPage() {
|
export function DashboardPage() {
|
||||||
const { dashboardCompact } = useUiStore();
|
const { dashboardCompact } = useUiStore();
|
||||||
@@ -23,16 +22,17 @@ export function DashboardPage() {
|
|||||||
const summary = summaryQuery.data;
|
const summary = summaryQuery.data;
|
||||||
const diseases = diseasesQuery.data ?? [];
|
const diseases = diseasesQuery.data ?? [];
|
||||||
|
|
||||||
const diseasesQuick = useMemo(() =>
|
const diseasesQuick = useMemo(
|
||||||
diseases
|
() =>
|
||||||
.sort((a, b) => a.displayOrder - b.displayOrder)
|
diseases
|
||||||
.map((d) => ({
|
.sort((a, b) => a.displayOrder - b.displayOrder)
|
||||||
name: d.commonName,
|
.map((d) => ({
|
||||||
sci: d.label,
|
name: d.commonName,
|
||||||
color: d.accentColor,
|
sci: d.label,
|
||||||
slug: d.slug,
|
color: d.accentColor,
|
||||||
})),
|
slug: d.slug,
|
||||||
[diseases]
|
})),
|
||||||
|
[diseases],
|
||||||
);
|
);
|
||||||
|
|
||||||
const missionCards = [
|
const missionCards = [
|
||||||
@@ -74,7 +74,11 @@ export function DashboardPage() {
|
|||||||
{/* Hero header */}
|
{/* Hero header */}
|
||||||
<header
|
<header
|
||||||
className="relative overflow-hidden rounded-3xl bg-cover bg-center bg-no-repeat shadow-sm"
|
className="relative overflow-hidden rounded-3xl bg-cover bg-center bg-no-repeat shadow-sm"
|
||||||
style={{ backgroundImage: `url(${bg})` }}
|
style={{
|
||||||
|
backgroundImage: `url(https://cdn.pixabay.com/photo/2014/09/09/19/07/corn-field-440338_1280.jpg)`,
|
||||||
|
backgroundPosition: "bottom",
|
||||||
|
backgroundSize: "cover",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="absolute inset-0 bg-gradient-to-b from-[#2F6E1A]/60 to-black/30" />
|
<div className="absolute inset-0 bg-gradient-to-b from-[#2F6E1A]/60 to-black/30" />
|
||||||
<div className="relative z-10 flex flex-col md:flex-row items-center justify-between gap-6 p-6 md:p-10">
|
<div className="relative z-10 flex flex-col md:flex-row items-center justify-between gap-6 p-6 md:p-10">
|
||||||
@@ -82,7 +86,9 @@ export function DashboardPage() {
|
|||||||
<span className="inline-block rounded-full bg-[#1E8A2A]/80 px-4 py-2 text-xs font-semibold">
|
<span className="inline-block rounded-full bg-[#1E8A2A]/80 px-4 py-2 text-xs font-semibold">
|
||||||
AI FOR SMART EDUCATION
|
AI FOR SMART EDUCATION
|
||||||
</span>
|
</span>
|
||||||
<h1 className="text-2xl md:text-4xl font-extrabold">Selamat Datang di</h1>
|
<h1 className="text-2xl md:text-4xl font-extrabold">
|
||||||
|
Selamat Datang di
|
||||||
|
</h1>
|
||||||
<h2 className="text-2xl md:text-4xl font-extrabold tracking-tight text-[#9AD872]">
|
<h2 className="text-2xl md:text-4xl font-extrabold tracking-tight text-[#9AD872]">
|
||||||
ZeaVis Edu
|
ZeaVis Edu
|
||||||
</h2>
|
</h2>
|
||||||
@@ -107,10 +113,7 @@ export function DashboardPage() {
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
className="px-4 md:px-6 py-3 md:py-6 text-sm md:text-lg font-semibold text-white hover:bg-[#1E8A2A]"
|
className="px-4 md:px-6 py-3 md:py-6 text-sm md:text-lg font-semibold text-white hover:bg-[#1E8A2A]"
|
||||||
>
|
>
|
||||||
<Link
|
<Link to="/catalog" className="inline-flex items-center gap-2">
|
||||||
to="/catalog"
|
|
||||||
className="inline-flex items-center gap-2"
|
|
||||||
>
|
|
||||||
Pustaka Penyakit
|
Pustaka Penyakit
|
||||||
<ChevronRight className="h-5 w-6" />
|
<ChevronRight className="h-5 w-6" />
|
||||||
</Link>
|
</Link>
|
||||||
@@ -169,7 +172,10 @@ export function DashboardPage() {
|
|||||||
<div className="text-3xl font-bold">
|
<div className="text-3xl font-bold">
|
||||||
{summary.imageClassificationCount}
|
{summary.imageClassificationCount}
|
||||||
</div>
|
</div>
|
||||||
<Link to="/diagnoses" className="text-emerald-600 ml-auto hover:underline">
|
<Link
|
||||||
|
to="/diagnoses"
|
||||||
|
className="text-emerald-600 ml-auto hover:underline"
|
||||||
|
>
|
||||||
Lihat daftar
|
Lihat daftar
|
||||||
</Link>
|
</Link>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
@@ -186,7 +192,10 @@ export function DashboardPage() {
|
|||||||
<div className="text-3xl font-bold text-amber-600">
|
<div className="text-3xl font-bold text-amber-600">
|
||||||
{summary.needsReviewCount}
|
{summary.needsReviewCount}
|
||||||
</div>
|
</div>
|
||||||
<Link to="/diagnoses?status=needs_review" className="text-amber-600 ml-auto hover:underline">
|
<Link
|
||||||
|
to="/diagnoses?status=needs_review"
|
||||||
|
className="text-amber-600 ml-auto hover:underline"
|
||||||
|
>
|
||||||
Lihat daftar
|
Lihat daftar
|
||||||
</Link>
|
</Link>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
@@ -200,10 +209,11 @@ export function DashboardPage() {
|
|||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="h-full flex flex-col justify-start pt-2">
|
<CardContent className="h-full flex flex-col justify-start pt-2">
|
||||||
<div className="text-3xl font-bold text-red-600">
|
<div className="text-3xl font-bold text-red-600">—</div>
|
||||||
—
|
<Link
|
||||||
</div>
|
to="/diagnoses?status=failed"
|
||||||
<Link to="/diagnoses?status=failed" className="text-red-600 ml-auto hover:underline">
|
className="text-red-600 ml-auto hover:underline"
|
||||||
|
>
|
||||||
Lihat daftar
|
Lihat daftar
|
||||||
</Link>
|
</Link>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
@@ -220,7 +230,10 @@ export function DashboardPage() {
|
|||||||
<div className="text-3xl font-bold text-red-600">
|
<div className="text-3xl font-bold text-red-600">
|
||||||
{summary.riskDistribution.high}
|
{summary.riskDistribution.high}
|
||||||
</div>
|
</div>
|
||||||
<Link to="/catalog?risk=high" className="text-red-600 ml-auto hover:underline">
|
<Link
|
||||||
|
to="/catalog?risk=high"
|
||||||
|
className="text-red-600 ml-auto hover:underline"
|
||||||
|
>
|
||||||
Lihat pustaka
|
Lihat pustaka
|
||||||
</Link>
|
</Link>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
@@ -276,7 +289,8 @@ export function DashboardPage() {
|
|||||||
Penyakit yang Dapat Dideteksi
|
Penyakit yang Dapat Dideteksi
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-[15px] font-normal text-muted-foreground">
|
<p className="text-[15px] font-normal text-muted-foreground">
|
||||||
{diseases.length} kelas penyakit dan kondisi daun jagung dalam sistem kami
|
{diseases.length} kelas penyakit dan kondisi daun jagung dalam
|
||||||
|
sistem kami
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Link
|
<Link
|
||||||
@@ -295,9 +309,7 @@ export function DashboardPage() {
|
|||||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4">
|
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4">
|
||||||
{diseasesQuick.map((d) => (
|
{diseasesQuick.map((d) => (
|
||||||
<Link key={d.slug} to={`/catalog/${d.slug}`}>
|
<Link key={d.slug} to={`/catalog/${d.slug}`}>
|
||||||
<Card
|
<Card className="rounded-2xl bg-white p-4 shadow-sm h-full transition-transform hover:scale-[1.03] hover:shadow-md cursor-pointer">
|
||||||
className="rounded-2xl bg-white p-4 shadow-sm h-full transition-transform hover:scale-[1.03] hover:shadow-md cursor-pointer"
|
|
||||||
>
|
|
||||||
<CardContent className="h-full p-4 flex flex-col justify-between">
|
<CardContent className="h-full p-4 flex flex-col justify-between">
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-start gap-3">
|
||||||
<div
|
<div
|
||||||
@@ -324,7 +336,9 @@ export function DashboardPage() {
|
|||||||
{/* Scan quick access */}
|
{/* Scan quick access */}
|
||||||
<div className="mt-12 flex flex-col sm:flex-row items-center gap-4 sm:gap-6 bg-[#1E8A2A] rounded-3xl p-5 sm:p-6">
|
<div className="mt-12 flex flex-col sm:flex-row items-center gap-4 sm:gap-6 bg-[#1E8A2A] rounded-3xl p-5 sm:p-6">
|
||||||
<div className="flex-1 text-white">
|
<div className="flex-1 text-white">
|
||||||
<h3 className="text-2xl font-bold">Siap Mendeteksi Penyakit Daun?</h3>
|
<h3 className="text-2xl font-bold">
|
||||||
|
Siap Mendeteksi Penyakit Daun?
|
||||||
|
</h3>
|
||||||
<p className="text-sm text-[#9AD872] font-normal mt-2">
|
<p className="text-sm text-[#9AD872] font-normal mt-2">
|
||||||
Unggah foto daun jagung Anda dan dapatkan hasil analisis AI
|
Unggah foto daun jagung Anda dan dapatkan hasil analisis AI
|
||||||
dalam hitungan detik.
|
dalam hitungan detik.
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ export function DiagnosesPage() {
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex items-center justify-between gap-4">
|
<div className="flex items-center justify-between gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl font-bold text-emerald-800">Diagnosa Tanaman</h1>
|
<h1 className="text-2xl font-bold text-emerald-800">Diagnosa Penyakit</h1>
|
||||||
<p className="text-gray-500 mt-1 text-md">
|
<p className="text-gray-500 mt-1 text-md">
|
||||||
Lihat hasil diagnosa dari scan yang telah dilakukan
|
Lihat hasil diagnosa dari scan yang telah dilakukan
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export function ExpertReviewsPage() {
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3">
|
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl font-bold text-emerald-800">Review Pakar</h1>
|
<h1 className="text-2xl font-bold text-emerald-800">Tinjauan Pakar</h1>
|
||||||
<p className="text-gray-500 mt-1 text-md">
|
<p className="text-gray-500 mt-1 text-md">
|
||||||
Tinjau hasil diagnosa dari scan yang telah dilakukan dan berikan
|
Tinjau hasil diagnosa dari scan yang telah dilakukan dan berikan
|
||||||
feedback untuk meningkatkan akurasi sistem AI ZeaVis Edu
|
feedback untuk meningkatkan akurasi sistem AI ZeaVis Edu
|
||||||
|
|||||||
@@ -65,15 +65,29 @@ export function LoginPage() {
|
|||||||
<main className="flex min-h-screen items-center justify-center px-6 py-12">
|
<main className="flex min-h-screen items-center justify-center px-6 py-12">
|
||||||
<div className="flex flex-col items-center gap-3">
|
<div className="flex flex-col items-center gap-3">
|
||||||
<div className="h-10 w-10 border-4 border-green-500 border-t-transparent rounded-full animate-spin" />
|
<div className="h-10 w-10 border-4 border-green-500 border-t-transparent rounded-full animate-spin" />
|
||||||
<p className="text-gray-500 text-sm">Menyelesaikan login dengan Google...</p>
|
<p className="text-gray-500 text-sm">
|
||||||
|
Menyelesaikan login dengan Google...
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="flex min-h-screen items-center justify-center px-6 py-12">
|
<main className="relative flex min-h-screen items-center justify-center px-6 py-12">
|
||||||
<div className="w-full max-w-sm md:max-w-md space-y-4">
|
{/* Background Image with Overlay */}
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 z-0"
|
||||||
|
style={{
|
||||||
|
backgroundImage: `linear-gradient(rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.4)), url(https://cdn.pixabay.com/photo/2014/09/09/19/07/corn-field-440338_1280.jpg)`,
|
||||||
|
backgroundSize: "cover",
|
||||||
|
backgroundPosition: "center",
|
||||||
|
backgroundRepeat: "no-repeat",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Glassmorphism Container */}
|
||||||
|
<div className="relative z-10 w-full max-w-sm md:max-w-md space-y-6 bg-white/60 backdrop-blur-md p-8 md:p-10 rounded-3xl shadow-2xl border border-white/50">
|
||||||
<AuthForm
|
<AuthForm
|
||||||
mode="login"
|
mode="login"
|
||||||
isSubmitting={mutation.isPending}
|
isSubmitting={mutation.isPending}
|
||||||
@@ -87,9 +101,13 @@ export function LoginPage() {
|
|||||||
}}
|
}}
|
||||||
onFieldChange={() => setError(null)}
|
onFieldChange={() => setError(null)}
|
||||||
/>
|
/>
|
||||||
<p className="text-center text-sm text-muted-foreground">
|
|
||||||
|
<p className="text-center text-sm text-slate-700">
|
||||||
Belum punya akun?{" "}
|
Belum punya akun?{" "}
|
||||||
<Link className="text-primary" to="/register">
|
<Link
|
||||||
|
className="text-emerald-700 font-bold hover:underline"
|
||||||
|
to="/register"
|
||||||
|
>
|
||||||
Daftar
|
Daftar
|
||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -28,7 +28,18 @@ export function RegisterPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="flex min-h-screen items-center justify-center px-6 py-12">
|
<main className="flex min-h-screen items-center justify-center px-6 py-12">
|
||||||
<div className="w-full max-w-sm md:max-w-md space-y-4">
|
{/* Background Image with Overlay */}
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 z-0"
|
||||||
|
style={{
|
||||||
|
backgroundImage: `linear-gradient(rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.4)), url(https://cdn.pixabay.com/photo/2014/09/09/19/07/corn-field-440338_1280.jpg)`,
|
||||||
|
backgroundSize: "cover",
|
||||||
|
backgroundPosition: "center",
|
||||||
|
backgroundRepeat: "no-repeat",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* Glassmorphism Container */}
|
||||||
|
<div className="relative z-10 w-full max-w-sm md:max-w-md space-y-6 bg-white/60 backdrop-blur-md p-8 md:p-10 rounded-3xl shadow-2xl border border-white/50">
|
||||||
<AuthForm
|
<AuthForm
|
||||||
mode="register"
|
mode="register"
|
||||||
isSubmitting={mutation.isPending}
|
isSubmitting={mutation.isPending}
|
||||||
|
|||||||
@@ -36,21 +36,18 @@ export function ScanPage() {
|
|||||||
|
|
||||||
// Camera mode state
|
// Camera mode state
|
||||||
const [useCamera, setUseCamera] = useState(false);
|
const [useCamera, setUseCamera] = useState(false);
|
||||||
const handleCameraCapture = useCallback(
|
const handleCameraCapture = useCallback((file: File) => {
|
||||||
(file: File) => {
|
setFileName(file.name);
|
||||||
setFileName(file.name);
|
const url = URL.createObjectURL(file);
|
||||||
const url = URL.createObjectURL(file);
|
setPreviewUrl(url);
|
||||||
setPreviewUrl(url);
|
|
||||||
|
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
setImageDimensions({ width: img.width, height: img.height });
|
setImageDimensions({ width: img.width, height: img.height });
|
||||||
};
|
};
|
||||||
img.src = url;
|
img.src = url;
|
||||||
setUseCamera(false);
|
setUseCamera(false);
|
||||||
},
|
}, []);
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const mutation = useMutation({
|
const mutation = useMutation({
|
||||||
mutationFn: (file: File) => apiClient.createDiagnosis(file),
|
mutationFn: (file: File) => apiClient.createDiagnosis(file),
|
||||||
@@ -107,10 +104,10 @@ export function ScanPage() {
|
|||||||
{/* Main Header */}
|
{/* Main Header */}
|
||||||
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-4">
|
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl font-bold text-emerald-800">Scan Tanaman</h1>
|
<h1 className="text-2xl font-bold text-emerald-800">Pindai Daun</h1>
|
||||||
<p className="text-gray-500 mt-1 text-md">
|
<p className="text-gray-500 mt-1 text-md">
|
||||||
Unggah foto daun jagung untuk dianalisis oleh sistem AI kami secara
|
Unggah foto daun jagung untuk dianalisis oleh sistem AI kami secara
|
||||||
real-time.
|
real-time
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Button asChild variant="outline">
|
<Button asChild variant="outline">
|
||||||
@@ -170,12 +167,16 @@ export function ScanPage() {
|
|||||||
className="w-full border-2 border-dashed border-green-300 rounded-md p-10 h-60 text-center cursor-pointer"
|
className="w-full border-2 border-dashed border-green-300 rounded-md p-10 h-60 text-center cursor-pointer"
|
||||||
onClick={() => inputRef.current?.click()}
|
onClick={() => inputRef.current?.click()}
|
||||||
>
|
>
|
||||||
<Upload className="mx-auto text-green-500 mb-3" size={48} />
|
<Upload
|
||||||
|
className="mx-auto text-green-500 mb-3"
|
||||||
|
size={48}
|
||||||
|
/>
|
||||||
<h3 className="font-semibold text-base text-gray-800 mb-1">
|
<h3 className="font-semibold text-base text-gray-800 mb-1">
|
||||||
Seret & Lepas Foto Daun
|
Seret & Lepas Foto Daun
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-xs text-gray-500 mb-3">
|
<p className="text-xs text-gray-500 mb-3">
|
||||||
atau klik untuk memilih file berkas dari perangkat Anda
|
atau klik untuk memilih file berkas dari perangkat
|
||||||
|
Anda
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-wrap gap-2 justify-center">
|
<div className="flex flex-wrap gap-2 justify-center">
|
||||||
<div className="bg-green-100 text-green-700 px-3 py-1 rounded-full inline-flex items-center gap-1 text-xs font-medium">
|
<div className="bg-green-100 text-green-700 px-3 py-1 rounded-full inline-flex items-center gap-1 text-xs font-medium">
|
||||||
|
|||||||
@@ -286,12 +286,11 @@ export function TelemetryPage() {
|
|||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl md:text-[28px] font-extrabold text-[#214B11] flex items-center gap-3">
|
<h1 className="text-2xl font-bold text-emerald-800">
|
||||||
<Activity className="h-7 w-7 text-[#48A111]" />
|
|
||||||
Telemetry Dashboard
|
Telemetry Dashboard
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-sm text-muted-foreground mt-0.5">
|
<p className="text-gray-500 mt-1 text-md">
|
||||||
Real-time metrics from Prometheus
|
Real-time monitoring dari performa sistem dan aplikasi ZeaVis Edu
|
||||||
{error && <span className="text-amber-600 ml-2">(partial — {error})</span>}
|
{error && <span className="text-amber-600 ml-2">(partial — {error})</span>}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -40,6 +40,9 @@
|
|||||||
"apps/tauri": {
|
"apps/tauri": {
|
||||||
"name": "@zeavis/tauri",
|
"name": "@zeavis/tauri",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
|
"dependencies": {
|
||||||
|
"sharp": "0.35.1",
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "^2",
|
"@tauri-apps/cli": "^2",
|
||||||
},
|
},
|
||||||
@@ -93,7 +96,7 @@
|
|||||||
|
|
||||||
"@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="],
|
"@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="],
|
||||||
|
|
||||||
"@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
|
"@emnapi/runtime": ["@emnapi/runtime@1.11.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw=="],
|
||||||
|
|
||||||
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="],
|
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="],
|
||||||
|
|
||||||
@@ -157,6 +160,60 @@
|
|||||||
|
|
||||||
"@grpc/proto-loader": ["@grpc/proto-loader@0.8.1", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.5.5", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-wtF6h+DY6M3YaDBPAmvuuA6jV8Sif9MjtOI5euKFWRgCDl5PeDpPsHR9u2l6St5ceY8AZgoNDww5+HvEsXFsGg=="],
|
"@grpc/proto-loader": ["@grpc/proto-loader@0.8.1", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.5.5", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-wtF6h+DY6M3YaDBPAmvuuA6jV8Sif9MjtOI5euKFWRgCDl5PeDpPsHR9u2l6St5ceY8AZgoNDww5+HvEsXFsGg=="],
|
||||||
|
|
||||||
|
"@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="],
|
||||||
|
|
||||||
|
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.35.1", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.3.0" }, "os": "darwin", "cpu": "arm64" }, "sha512-T15JRWOubQ3f5+GxnWeIvo47u5qV0M9HBgJhT+f2gE1e9e6OhR6K73Re52Hm80qWcu1DNb3GweKmpr/MnuP2Ow=="],
|
||||||
|
|
||||||
|
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.35.1", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.3.0" }, "os": "darwin", "cpu": "x64" }, "sha512-t1CPD0cr7XCHjwUj6tQ5MC0pCi866I+gUW6zbUX4aFPnKd1DFBtk0M+gWcjX8VeEzgfCNiSiNTVFZ6b7kvdbnQ=="],
|
||||||
|
|
||||||
|
"@img/sharp-freebsd-wasm32": ["@img/sharp-freebsd-wasm32@0.35.1", "", { "dependencies": { "@img/sharp-wasm32": "0.35.1" }, "os": "freebsd" }, "sha512-MBSQXqNPThW9EcZ905H6N4sEdX5EwZEYzGx5EBq9ncDCGJALMiY1xPFJxNdzuB1iBjLOpIfxajM6YxdvwmQSLA=="],
|
||||||
|
|
||||||
|
"@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.3.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-EKbmBKtyTH+GPFDRw2TgK2oV6hyxxlJVIar4hoTYSNmIwipgMFdxPQqR392GmfdsPGWga0mCFN1cCKjRb9cljw=="],
|
||||||
|
|
||||||
|
"@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.3.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Pl2OmOvrJ42adUllESxBsG54PfXLo1OYg9i3c5/5Ln/qJ0gZuTM9YMhQJPIbXqwidLRc/c2zuHt4RsrymmNv7A=="],
|
||||||
|
|
||||||
|
"@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.3.0", "", { "os": "linux", "cpu": "arm" }, "sha512-A8UpHoUDW4DwnXoV6+q3C1s7QLRAHtPDEjWuNZjwHMyoCNZnm0GeNN8ls9f/bsEYTRQRW96C/n34XJQHJ2fT7A=="],
|
||||||
|
|
||||||
|
"@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-C0SqjoFKnszqa44EQ7xoaT48nnO0lOyXEULfXMWi8krrjOPGYkeK30Okzla6ATbBYsyZ0ySinK0FVkpv3DwzfQ=="],
|
||||||
|
|
||||||
|
"@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.3.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WOpkVxAjFd369iaIzEgNRreFD+gWdUMIGD5zplhNKNeqS6mm5dac3q2AFyCBmzYoAdouzZvRBgxy4z8QHZb4/A=="],
|
||||||
|
|
||||||
|
"@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.3.0", "", { "os": "linux", "cpu": "none" }, "sha512-DRWw0mOHusrCCuw2rqP87oLg6PGlkomVDFqw2hIwsSfwWpu4k3XLcBPaKKl6ct/GtL/cwNkgwjV/tc0Mqht3VA=="],
|
||||||
|
|
||||||
|
"@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.3.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-9APy+nFWhHS+kzLgWZfLcyrUd7YqnAQVa4BPOo4xkoHpdoktOAPG4cEr9+Jpl0TtqfVmcMJimNL5qNTyyOHZNA=="],
|
||||||
|
|
||||||
|
"@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-y9RNUYDe2A1UAdhLyfeOodGRszQdaEoe4nfOpp/sNVPl2CWIcUyFaDoCh4vPLPxu19803j2naLqZup2WxDXCLA=="],
|
||||||
|
|
||||||
|
"@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-cC1wkC0Mlucd0KSiGrLkJnB/ZqPvZCntc/Lk7ZnYO5ZSbF2euNek4Xvxafojq+wN1q/W0eprdpUIjUr/EV2PBg=="],
|
||||||
|
|
||||||
|
"@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-LiYMhUZicB1QG//+RvmYZpXJO8fYRENfp+MZUCnG9aw+AKvGAy9gPaCnuwsPcBFs8EV66M0NNxj9VHcNklE8zw=="],
|
||||||
|
|
||||||
|
"@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.35.1", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.3.0" }, "os": "linux", "cpu": "arm" }, "sha512-jygmR02PpCYypt7xB7nst1vqjZp/BpRA/Kf9nK7qRponJ/KrLPaZWEG4G15z1d2FZ6XqI+T0350ha3RSnKx24A=="],
|
||||||
|
|
||||||
|
"@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.35.1", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.3.0" }, "os": "linux", "cpu": "arm64" }, "sha512-ErCRyGU7LeoaFBZ0xW8hhLlXzhAg80sc4vxePB86qvtEvW1jEhhmbiNBP4oEzZfPMnu6HwHXfzD2W2kBU+RnCw=="],
|
||||||
|
|
||||||
|
"@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.35.1", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.3.0" }, "os": "linux", "cpu": "ppc64" }, "sha512-LUWZ2+r2UoLCd8j0RLCwQ4gL6w47+Y7igxtVnPIDXOOEjV86LpBkAHq5VpJeg+GHbw0KN/JWlPJOdZjyZnFqFQ=="],
|
||||||
|
|
||||||
|
"@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.35.1", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.3.0" }, "os": "linux", "cpu": "none" }, "sha512-i7x6J3mwF4JgT0sM4V4WlAWdJ0bucPtA9rzO1bTji1n5qgBq/W5nn87RvOQPleuuxahNoLdTngByD8/vDDLArw=="],
|
||||||
|
|
||||||
|
"@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.35.1", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.3.0" }, "os": "linux", "cpu": "s390x" }, "sha512-0zSaTUjTF0kIWTSYxD4EG/nvCU4jez53+3RdURtoY3HvbXtIQ98W90JnrGz/oLRFuEnfIy9+7xeq883euc0ZWw=="],
|
||||||
|
|
||||||
|
"@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.35.1", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.3.0" }, "os": "linux", "cpu": "x64" }, "sha512-NbJD4mWdeyrNQKluO/tR/wBDOelcowSVGNBWxI0e3ZtlXc6F/UOVKDj1MLD4zl3oHTuvKW3s+MA9N54YTldAYw=="],
|
||||||
|
|
||||||
|
"@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.35.1", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.3.0" }, "os": "linux", "cpu": "arm64" }, "sha512-VoW2sQCWI+0YIKQEmWJ8vzaQjTg9wIyfkFpvEfAS2h43X6iHu7GTk1hhOgB4IpSzCHe8UwQZIcx7b81VTaOrJA=="],
|
||||||
|
|
||||||
|
"@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.35.1", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.3.0" }, "os": "linux", "cpu": "x64" }, "sha512-LjBoSd/c5JU0/K5MwzDMlgsSRP2bPn98JQGFFQAOLQ0bU/1z4ekxUdSKY9BmlwSh/cA+OrvpgsWqfZyYfVHBRw=="],
|
||||||
|
|
||||||
|
"@img/sharp-wasm32": ["@img/sharp-wasm32@0.35.1", "", { "dependencies": { "@emnapi/runtime": "^1.11.0" } }, "sha512-PCQUoQdZyE8tp3HpbevuihfUmgSP4qWI0FGEPWoeXqaS+cUrFfemabHQiebUmUmlUhCuNnQMxGrQ+CPqK4hnxg=="],
|
||||||
|
|
||||||
|
"@img/sharp-webcontainers-wasm32": ["@img/sharp-webcontainers-wasm32@0.35.1", "", { "dependencies": { "@img/sharp-wasm32": "0.35.1" }, "cpu": "none" }, "sha512-xU2ml2bU2OPxYVvW2A6ae4M1g5QKyhKG06P4FAt+YEaFQQO0919Qx+XxIZEUuWTMoDViLpMws2/dQwoe/VcA6A=="],
|
||||||
|
|
||||||
|
"@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.35.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-IkmHwuFhYpd3bTsN5SAahjwhiAcyXPooBt8vEUgxY3T0IP70sSJ0nU1xiPzZY8AH/OB1XpV3j8aZSVSOSfTbdA=="],
|
||||||
|
|
||||||
|
"@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.35.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-wQahqCi9MD8Yxzg4gVM4fNrZxh+r6vD55PyIg+WJPaM5ZRUyF35iQpwJCuma3r6viU9/8Pxlc+XHV+woVa6nCQ=="],
|
||||||
|
|
||||||
|
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.35.1", "", { "os": "win32", "cpu": "x64" }, "sha512-WzBtkYtZHATLPe8XRharxZXxQ9cdLrQWHiwxt+BJ5rBsisQrKeeV86ErxPSVhcG6xCEuNhs0SqLpWr7XDa2k6w=="],
|
||||||
|
|
||||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||||
|
|
||||||
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
|
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
|
||||||
@@ -615,8 +672,12 @@
|
|||||||
|
|
||||||
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||||
|
|
||||||
|
"semver": ["semver@7.8.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA=="],
|
||||||
|
|
||||||
"set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="],
|
"set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="],
|
||||||
|
|
||||||
|
"sharp": ["sharp@0.35.1", "", { "dependencies": { "@img/colour": "^1.1.0", "detect-libc": "^2.1.2", "semver": "^7.8.4" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.35.1", "@img/sharp-darwin-x64": "0.35.1", "@img/sharp-freebsd-wasm32": "0.35.1", "@img/sharp-libvips-darwin-arm64": "1.3.0", "@img/sharp-libvips-darwin-x64": "1.3.0", "@img/sharp-libvips-linux-arm": "1.3.0", "@img/sharp-libvips-linux-arm64": "1.3.0", "@img/sharp-libvips-linux-ppc64": "1.3.0", "@img/sharp-libvips-linux-riscv64": "1.3.0", "@img/sharp-libvips-linux-s390x": "1.3.0", "@img/sharp-libvips-linux-x64": "1.3.0", "@img/sharp-libvips-linuxmusl-arm64": "1.3.0", "@img/sharp-libvips-linuxmusl-x64": "1.3.0", "@img/sharp-linux-arm": "0.35.1", "@img/sharp-linux-arm64": "0.35.1", "@img/sharp-linux-ppc64": "0.35.1", "@img/sharp-linux-riscv64": "0.35.1", "@img/sharp-linux-s390x": "0.35.1", "@img/sharp-linux-x64": "0.35.1", "@img/sharp-linuxmusl-arm64": "0.35.1", "@img/sharp-linuxmusl-x64": "0.35.1", "@img/sharp-webcontainers-wasm32": "0.35.1", "@img/sharp-win32-arm64": "0.35.1", "@img/sharp-win32-ia32": "0.35.1", "@img/sharp-win32-x64": "0.35.1" } }, "sha512-lW979AMi+ESidzMv/Lnv+F9bknzLyxLqFI05Sm433vOeRcltgxQmXpnfOOFIAlKtwXU/ksupm2srQoFCkR214g=="],
|
||||||
|
|
||||||
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||||
|
|
||||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||||
@@ -681,6 +742,8 @@
|
|||||||
|
|
||||||
"@reduxjs/toolkit/immer": ["immer@11.1.8", "", {}, "sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA=="],
|
"@reduxjs/toolkit/immer": ["immer@11.1.8", "", {}, "sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
|
||||||
|
|||||||
Reference in New Issue
Block a user