Progress Tampilan UI Dashboard Desa Plus NOC

This commit is contained in:
2026-03-17 20:53:33 +07:00
parent 8c35d58b38
commit f0c37272b9
21 changed files with 574 additions and 435 deletions

302
PromptDashboard.md Normal file
View File

@@ -0,0 +1,302 @@
Buat halaman dashboard admin modern untuk sistem pemerintahan desa bernama **Darmasaba Dashboard NOC**.
Gunakan stack berikut:
Frontend:
* React 19
* Bun runtime
* Vite
* TailwindCSS
* Mantine UI
* Mantine Charts atau Recharts
* Tabler Icons
* TanStack Router
* Dayjs
UI harus modular dengan reusable components.
Gunakan **TailwindCSS sebagai styling utama** dengan warna dari konfigurasi berikut:
Primary:
darmasaba-navy (#1E3A5F)
Secondary:
darmasaba-blue (#3B82F6)
Success:
#22C55E
Warning:
#FACC15
Danger:
#EF4444
Background:
#F5F8FB
Dashboard harus memiliki **Light Mode dan Dark Mode**.
Dark Mode Color Rules:
background: #0F172A
card: #1E293B
border: #334155
text: #E2E8F0
Card style:
* rounded-xl
* soft shadow
* padding besar
* border subtle
* smooth hover animation
Gunakan grid layout responsive.
---
SECTION 1 — PROGRAM KEGIATAN
Buat 4 card horizontal di bagian atas yang menampilkan kegiatan desa.
Setiap card memiliki:
* header biru
* progress bar kegiatan
* tanggal kegiatan
* badge status
Data card:
1.
Judul: Rakor 2025
Tanggal: 3 Juli 2025
Progress: 90%
Status: selesai
2.
Judul: Pemutakhiran Indeks Desa
Tanggal: 3 Juli 2025
Progress: 85%
Status: selesai
3.
Judul: Mengurus Akta Cerai Warga
Tanggal: 3 Juli 2025
Progress: 80%
Status: selesai
4.
Judul: Pasek 7 Desa Adat
Tanggal: 3 Juli 2025
Progress: 92%
Status: selesai
Progress bar:
* rounded
* warna warning
* animasi smooth
Status badge:
* success color
---
SECTION 2 — GRID DASHBOARD
Layout:
3 column grid.
Left column (sidebar style):
Divisi Teraktif
List item card dengan arrow icon.
Data:
Kesejahteraan — 37 kegiatan
Pemerintahan — 26 kegiatan
Keuangan — 17 kegiatan
Sekretaris Desa — 15 kegiatan
Tata Usaha TK — 14 kegiatan
Perangkat Kewilayahan — 12 kegiatan
Pelayanan — 10 kegiatan
Perencanaan — 9 kegiatan
Tata Usaha & Umum — 7 kegiatan
Setiap item:
* rounded
* hover effect
* arrow icon kanan
---
Middle column:
Jumlah Dokumen
Gunakan **Bar Chart**.
Kategori:
* Gambar
* Dokumen
Nilai:
* Gambar: 300
* Dokumen: 310
Gunakan:
Recharts atau Mantine Charts.
---
Right column:
Progres Kegiatan
Gunakan **Pie Chart**.
Data:
Selesai — 83.33%
Dikerjakan — 16.67%
Segera Dikerjakan — 0%
Dibatalkan — 0%
Legend harus berwarna.
---
SECTION 3 — DISCUSSION PANEL
Judul: Diskusi
Tampilkan list diskusi internal staf.
Item card memiliki:
* icon chat
* judul pesan
* nama pengirim
* tanggal
Contoh data:
"Kepada Pelayanan, mohon di cek..."
Pengirim: I.B Surya Prabhawa Manu
Tanggal: 12 Apr 2025
"Kepada staf perencanaan @suar..."
Pengirim: Ni Nyoman Yuliani
Tanggal: 14 Jun 2025
"ijin atau mohon kepada KBD sar..."
Pengirim: Ni Wayan Martini
Tanggal: 12 Apr 2025
---
SECTION 4 — ACARA HARI INI
Card sederhana.
Jika tidak ada acara tampilkan:
"Tidak ada acara hari ini"
---
SECTION 5 — ARSIP DIGITAL PERANGKAT DESA
Grid 2 column.
Menu arsip:
Surat Keputusan
Dokumentasi
Laporan Keuangan
Notulensi Rapat
Setiap item berupa card clickable dengan:
* icon dokumen
* border
* hover effect
---
DESIGN STYLE
Gunakan gaya:
Modern Government Dashboard
Clean UI
Soft shadow
Rounded-xl
Spacing besar
Minimalistic
---
RESPONSIVE RULES
Desktop:
12 column grid
Tablet:
6 column grid
Mobile:
single column stack
---
COMPONENT STRUCTURE
src/components/dashboard
activity-card.tsx
division-list.tsx
document-chart.tsx
progress-chart.tsx
discussion-panel.tsx
event-card.tsx
archive-card.tsx
src/pages
dashboard.tsx
---
CODE QUALITY
Gunakan:
* React hooks
* reusable components
* Mantine components jika perlu
* Tailwind utility classes
* dark mode support
* responsive layout
* clean TypeScript
---
Output:
* Halaman dashboard lengkap
* Semua komponen reusable
* Chart sudah bekerja
* Layout identik dengan desain dashboard modern pemerintahan

View File

@@ -1,4 +1,4 @@
import { Grid, Stack, useMantineColorScheme } from "@mantine/core"; import { Grid, Image, Stack, useMantineColorScheme } from "@mantine/core";
import { CheckCircle, FileText, MessageCircle, Users } from "lucide-react"; import { CheckCircle, FileText, MessageCircle, Users } from "lucide-react";
import { ActivityList } from "./dashboard/activity-list"; import { ActivityList } from "./dashboard/activity-list";
import { ChartAPBDes } from "./dashboard/chart-apbdes"; import { ChartAPBDes } from "./dashboard/chart-apbdes";
@@ -8,149 +8,26 @@ import { SatisfactionChart } from "./dashboard/satisfaction-chart";
import { SDGSCard } from "./dashboard/sdgs-card"; import { SDGSCard } from "./dashboard/sdgs-card";
import { StatCard } from "./dashboard/stat-card"; import { StatCard } from "./dashboard/stat-card";
// SDGs Icons
function EnergyIcon() {
return (
<svg
width="48"
height="48"
viewBox="0 0 48 48"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M24 4L14 24H22L20 44L34 20H26L24 4Z"
fill="currentColor"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
function PeaceIcon() {
return (
<svg
width="48"
height="48"
viewBox="0 0 48 48"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="24" cy="24" r="20" stroke="currentColor" strokeWidth="2" />
<path
d="M24 4V44M24 24L10 38M24 24L38 38"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
/>
</svg>
);
}
function HealthIcon() {
return (
<svg
width="48"
height="48"
viewBox="0 0 48 48"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M24 44C24 44 6 28 6 18C6 11.373 11.373 6 18 6C21.5 6 24.5 7.5 24 12C23.5 7.5 26.5 6 30 6C36.627 6 42 11.373 42 18C42 28 24 44 24 44Z"
fill="currentColor"
stroke="currentColor"
strokeWidth="2"
strokeLinejoin="round"
/>
</svg>
);
}
function PovertyIcon() {
return (
<svg
width="48"
height="48"
viewBox="0 0 48 48"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect x="6" y="18" width="36" height="26" rx="2" fill="currentColor" />
<path
d="M14 18V12C14 8.686 16.686 6 20 6H28C31.314 6 34 8.686 34 12V18"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
/>
</svg>
);
}
function OceanIcon() {
return (
<svg
width="48"
height="48"
viewBox="0 0 48 48"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 30C6 30 10 26 14 30C18 34 22 30 26 30C30 30 34 34 38 30C42 26 46 30 46 30"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
/>
<path
d="M6 38C6 38 10 34 14 38C18 42 22 38 26 38C30 38 34 42 38 38C42 34 46 38 46 38"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
/>
<circle cx="24" cy="16" r="6" fill="currentColor" />
</svg>
);
}
const sdgsData = [ const sdgsData = [
{ {
title: "Desa Berenergi Bersih dan Terbarukan", title: "Desa Berenergi Bersih dan Terbarukan",
score: 99.64, score: 99.64,
icon: <EnergyIcon />, image: "SDGS-7.png",
color: "#FACC15",
bgColor: "#FEF9C3",
}, },
{ {
title: "Desa Damai Berkeadilan", title: "Desa Damai Berkeadilan",
score: 78.65, score: 78.65,
icon: <PeaceIcon />, image: "SDGS-16.png",
color: "#3B82F6",
bgColor: "#DBEAFE",
}, },
{ {
title: "Desa Sehat dan Sejahtera", title: "Desa Sehat dan Sejahtera",
score: 77.37, score: 77.37,
icon: <HealthIcon />, image: "SDGS-3.png",
color: "#22C55E",
bgColor: "#DCFCE7",
}, },
{ {
title: "Desa Tanpa Kemiskinan", title: "Desa Tanpa Kemiskinan",
score: 52.62, score: 52.62,
icon: <PovertyIcon />, image: "SDGS-1.png",
color: "#EF4444",
bgColor: "#FEE2E2",
},
{
title: "Desa Peduli Lingkungan Laut",
score: 50.0,
icon: <OceanIcon />,
color: "#06B6D4",
bgColor: "#CFFAFE",
}, },
]; ];
@@ -202,37 +79,35 @@ export function DashboardContent() {
{/* Section 2: Chart & Division Progress */} {/* Section 2: Chart & Division Progress */}
<Grid gutter="lg"> <Grid gutter="lg">
<Grid.Col span={{ base: 12, lg: 8 }}> <Grid.Col span={{ base: 12, lg: 7 }}>
<ChartSurat /> <ChartSurat />
</Grid.Col> </Grid.Col>
<Grid.Col span={{ base: 12, lg: 4 }}> <Grid.Col span={{ base: 12, lg: 5 }}>
<DivisionProgress />
</Grid.Col>
</Grid>
{/* Section 3: APBDes Chart */}
<ChartAPBDes />
{/* Section 4 & 5: Activity List & Satisfaction Chart */}
<Grid gutter="lg">
<Grid.Col span={{ base: 12, lg: 6 }}>
<ActivityList />
</Grid.Col>
<Grid.Col span={{ base: 12, lg: 6 }}>
<SatisfactionChart /> <SatisfactionChart />
</Grid.Col> </Grid.Col>
</Grid> </Grid>
{/* Section 3: APBDes Chart */}
<Grid gutter="lg">
<Grid.Col span={{ base: 12, lg: 7 }}>
<DivisionProgress />
</Grid.Col>
<Grid.Col span={{ base: 12, lg: 5 }}>
<ActivityList />
{/* <SatisfactionChart /> */}
</Grid.Col>
</Grid>
<ChartAPBDes />
{/* Section 6: SDGs Desa Cards */} {/* Section 6: SDGs Desa Cards */}
<Grid gutter="md"> <Grid gutter="md">
{sdgsData.map((sdg, index) => ( {sdgsData.map((sdg, index) => (
<Grid.Col key={index} span={{ base: 12, sm: 6, md: 4, lg: 2.4 }}> <Grid.Col key={index} span={{ base: 9, md: 3 }}>
<SDGSCard <SDGSCard
image={<Image src={sdg.image} alt={sdg.title} />}
title={sdg.title} title={sdg.title}
score={sdg.score} score={sdg.score}
icon={sdg.icon}
color={sdg.color}
bgColor={sdg.bgColor}
/> />
</Grid.Col> </Grid.Col>
))} ))}

View File

@@ -4,18 +4,10 @@ import type { ReactNode } from "react";
interface SDGSCardProps { interface SDGSCardProps {
title: string; title: string;
score: number; score: number;
icon: ReactNode; image: ReactNode;
color: string;
bgColor: string;
} }
export function SDGSCard({ export function SDGSCard({ title, score, image }: SDGSCardProps) {
title,
score,
icon,
color,
bgColor,
}: SDGSCardProps) {
const { colorScheme } = useMantineColorScheme(); const { colorScheme } = useMantineColorScheme();
const dark = colorScheme === "dark"; const dark = colorScheme === "dark";
@@ -24,29 +16,28 @@ export function SDGSCard({
p="md" p="md"
radius="xl" radius="xl"
withBorder withBorder
bg={bgColor}
style={{ style={{
borderColor: dark ? "#334155" : bgColor, borderColor: dark ? "#334155" : "white",
boxShadow: "0 1px 3px 0 rgb(0 0 0 / 0.1)", boxShadow: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
}} }}
h="100%"
> >
<Group justify="space-between" align="flex-start" w="100%"> <Group justify="space-between" align="flex-start" w="100%">
<Box>{image}</Box>
<Box style={{ flex: 1 }}> <Box style={{ flex: 1 }}>
<Text size="sm" c={dark ? "white" : "gray.8"} fw={500} mb="xs"> <Text
ta={"center"}
size="sm"
c={dark ? "white" : "gray.8"}
fw={500}
mb="xs"
>
{title} {title}
</Text> </Text>
<Text size="xl" fw={700} c={color}> <Text ta={"center"} size="xl" c={dark ? "white" : "gray.8"} fw={700}>
{score.toFixed(2)} {score.toFixed(2)}
</Text> </Text>
</Box> </Box>
<Box
style={{
color,
opacity: 0.8,
}}
>
{icon}
</Box>
</Group> </Group>
</Card> </Card>
); );

View File

@@ -1,13 +1,12 @@
import { Grid, Stack } from "@mantine/core"; import { Grid, Stack } from "@mantine/core";
import { import { ActivityCard, } from "./kinerja-divisi/activity-card";
ActivityCard, import { DivisionList } from "./kinerja-divisi/division-list";
ArchiveCard, import { DocumentChart } from "./kinerja-divisi/document-chart";
DiscussionPanel, import { ProgressChart } from "./kinerja-divisi/progress-chart";
DivisionList, import { DiscussionPanel } from "./kinerja-divisi/discussion-panel";
DocumentChart, import { EventCard } from "./kinerja-divisi/event-card";
EventCard, import { ArchiveCard } from "./kinerja-divisi/archive-card";
ProgressChart,
} from ".";
// Data for program kegiatan (Section 1) // Data for program kegiatan (Section 1)
const programKegiatanData = [ const programKegiatanData = [

View File

@@ -3,6 +3,7 @@ import {
Box, Box,
Collapse, Collapse,
Group, Group,
Image,
Input, Input,
NavLink as MantineNavLink, NavLink as MantineNavLink,
Stack, Stack,
@@ -60,30 +61,7 @@ export function Sidebar({ className }: SidebarProps) {
return ( return (
<Box className={className}> <Box className={className}>
{/* Logo */} {/* Logo */}
<Box <Image src="/logo-desa-plus.png" alt="Logo" />
p="md"
style={{ borderBottom: "1px solid var(--mantine-color-gray-3)" }}
>
<Group gap="xs">
<Badge
color="dark"
variant="filled"
size="xl"
radius="md"
py="xs"
px="md"
style={{ fontSize: "1.5rem", fontWeight: "bold" }}
>
DESA
</Badge>
<Badge color="green" variant="filled" size="md" radius="md">
+
</Badge>
</Group>
<Text size="xs" c="dimmed" mt="xs">
Digitalisasi Desa Transparansi Kerja
</Text>
</Box>
{/* Search */} {/* Search */}
<Box p="md"> <Box p="md">

View File

@@ -1,11 +1,10 @@
import { import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core";
AppShell,
Burger,
Group,
useMantineColorScheme,
} from "@mantine/core";
import { useDisclosure, useMediaQuery } from "@mantine/hooks"; import { useDisclosure, useMediaQuery } from "@mantine/hooks";
import { createFileRoute, Outlet, useRouterState } from "@tanstack/react-router"; import {
createFileRoute,
Outlet,
useRouterState,
} from "@tanstack/react-router";
import { useEffect } from "react"; import { useEffect } from "react";
import { Header } from "@/components/header"; import { Header } from "@/components/header";
import { Sidebar } from "@/components/sidebar"; import { Sidebar } from "@/components/sidebar";
@@ -44,12 +43,7 @@ function PengaturanLayout() {
> >
<AppShell.Header bg={headerBgColor}> <AppShell.Header bg={headerBgColor}>
<Group h="100%" px="lg" align="center" wrap="nowrap"> <Group h="100%" px="lg" align="center" wrap="nowrap">
<Burger <Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
opened={opened}
onClick={toggle}
hiddenFrom="sm"
size="sm"
/>
<Header /> <Header />
</Group> </Group>
</AppShell.Header> </AppShell.Header>