main
Ilham Wara Nugroho 2026-07-20 13:21:05 +07:00
parent d0e1e97254
commit 6bc16bcdad
22 changed files with 2512 additions and 303 deletions

View File

@ -44,218 +44,6 @@ public class HomeController : Controller
TotalFauna = 30,
TotalSpecies = 80
},
FeaturedSpesies = new List<SpesiesModel>
{
new()
{
Slug = "pohon-trembesi",
Type = "flora",
CommonName = "Pohon Trembesi",
ScientificName = "Samanea saman",
Description =
"Pohon peneduh raksasa dengan tajuk lebar menyerupai payung. Sangat efektif menyerap karbon dioksida sehingga banyak ditanam di ruang publik Jakarta.",
Habitat = "Tumbuh baik di dataran rendah tropis, tanah subur, sinar matahari penuh.",
ConservationStatus = "Aman",
Image = "sp-trembesi.jpg",
LocationSlugs = new List<string>
{
"tebet-eco-park",
"hutan-kota-gbk",
"taman-menteng"
}
},
new()
{
Slug= "pohon-beringin",
Type= "flora",
CommonName= "Pohon Beringin",
ScientificName= "Ficus benjamina",
Description=
"Pohon rindang dengan akar udara khas yang menjuntai. Simbol keteduhan dan sering dijumpai di taman kota serta ruang publik Jakarta.",
Habitat= "Iklim tropis, tanah lembab, tahan terhadap polusi udara perkotaan.",
ConservationStatus= "Aman",
Image= "sp-beringin.jpg",
LocationSlugs = new List<string>
{"hutan-kota-srengseng", "taman-menteng", "hutan-kota-gbk"}
},
new()
{
Slug= "mangrove-rhizophora",
Type= "flora",
CommonName= "Bakau Merah",
ScientificName= "Rhizophora mucronata",
Description=
"Tumbuhan bakau dengan akar tunjang khas. Berfungsi sebagai benteng alami pesisir Jakarta terhadap abrasi dan intrusi air laut.",
Habitat= "Kawasan pesisir berlumpur, muara sungai, air payau.",
ConservationStatus= "Dilindungi",
Image= "sp-mangrove.jpg",
LocationSlugs = new List<string>
{"muara-angke", "mangrove-pik"}
},
new()
{
Slug= "bunga-kamboja",
Type= "flora",
CommonName= "Kamboja Putih",
ScientificName= "Plumeria alba",
Description=
"Pohon hias berbunga harum dengan kelopak putih dan kuning di tengah. Populer di pekarangan dan taman kota.",
Habitat= "Daerah tropis kering, tanah berdrainase baik.",
ConservationStatus= "Aman",
Image= "sp-kamboja.jpg",
LocationSlugs = new List<string>
{"tebet-eco-park", "taman-menteng"}
},
new()
{
Slug= "anggrek-bulan",
Type= "flora",
CommonName= "Anggrek Bulan",
ScientificName= "Phalaenopsis amabilis",
Description=
"Bunga nasional Indonesia (Puspa Pesona). Berkelopak lebar putih murni, tumbuh menempel pada batang pohon.",
Habitat= "Epifit pada pohon di hutan tropis lembab.",
ConservationStatus= "Rentan",
Image= "sp-anggrek.jpg",
LocationSlugs = new List<string>
{"hutan-kota-srengseng", "tebet-eco-park"}
},
new()
{
Slug= "bambu-kuning",
Type= "flora",
CommonName= "Bambu Kuning",
ScientificName= "Bambusa vulgaris",
Description=
"Rumpun bambu berbatang kuning cerah yang tumbuh cepat. Berperan penting menyerap air tanah dan mencegah erosi.",
Habitat= "Tanah lembab di tepi sungai, taman, dan hutan kota.",
ConservationStatus= "Aman",
Image= "sp-bambu.jpg",
LocationSlugs = new List<string>
{"tebet-eco-park", "hutan-kota-srengseng"}
},
new()
{
Slug= "burung-kutilang",
Type= "fauna",
CommonName= "Burung Kutilang",
ScientificName= "Pycnonotus aurigaster",
Description=
"Burung pengicau kecil dengan tunggir kuning cerah. Salah satu burung liar paling umum di taman-taman Jakarta.",
Habitat= "Taman kota, pekarangan, hutan sekunder.",
ConservationStatus= "Aman",
Image= "sp-kutilang.jpg",
LocationSlugs = new List<string>
{"tebet-eco-park", "taman-menteng", "hutan-kota-gbk"}
},
new()
{
Slug= "burung-madu-sriganti",
Type= "fauna",
CommonName= "Burung Madu Sriganti",
ScientificName= "Cinnyris jugularis",
Description=
"Burung kecil berwarna cerah, jantan berdada hitam berkilau. Penghisap nektar bunga di taman dan hutan kota.",
Habitat= "Taman berbunga, semak berbunga, pinggir hutan.",
ConservationStatus= "Dilindungi",
Image= "sp-madu-sriganti.jpg",
LocationSlugs = new List<string>
{"tebet-eco-park", "hutan-kota-srengseng", "mangrove-pik"}
},
new()
{
Slug= "kupu-kupu-raja",
Type= "fauna",
CommonName= "Kupu-kupu Raja",
ScientificName= "Papilio memnon",
Description=
"Kupu-kupu besar berwarna hitam kebiruan dengan sayap lebar. Penyerbuk penting bagi berbagai tanaman berbunga.",
Habitat= "Taman berbunga, hutan sekunder, pinggir sungai.",
ConservationStatus= "Aman",
Image= "sp-kupu-kupu.jpg",
LocationSlugs = new List<string>
{"tebet-eco-park", "hutan-kota-srengseng"}
},
new()
{
Slug= "biawak-air",
Type= "fauna",
CommonName= "Biawak Air",
ScientificName= "Varanus salvator",
Description=
"Reptil besar semi-akuatik dengan lidah bercabang. Predator alami yang membantu mengendalikan populasi tikus di ekosistem kota.",
Habitat= "Rawa, sungai, hutan mangrove.",
ConservationStatus= "Dilindungi",
Image= "sp-biawak.jpg",
LocationSlugs = new List<string>
{"muara-angke", "mangrove-pik"}
},
new()
{
Slug= "monyet-ekor-panjang",
Type= "fauna",
CommonName= "Monyet Ekor Panjang",
ScientificName= "Macaca fascicularis",
Description=
"Primata berbulu abu-abu kecoklatan dengan ekor panjang. Hidup berkelompok di kawasan hutan yang tersisa.",
Habitat= "Hutan mangrove, hutan sekunder, tepi sungai.",
ConservationStatus= "Rentan",
Image= "sp-monyet.jpg",
LocationSlugs = new List<string>
{"muara-angke", "mangrove-pik"}
},
new()
{
Slug= "elang-bondol",
Type= "fauna",
CommonName= "Elang Bondol",
ScientificName= "Haliastur indus",
Description=
"Elang berkepala putih dengan tubuh coklat kemerahan. Maskot Provinsi DKI Jakarta dan simbol kekayaan hayati pesisir.",
Habitat= "Pesisir, mangrove, muara sungai.",
ConservationStatus= "Dilindungi",
Image= "sp-elang-bondol.jpg",
LocationSlugs = new List<string>
{"muara-angke", "mangrove-pik"}
},
},
FeaturedLocations = new List<LokasiModel>
{
new()
{
Slug = "tebet-eco-park",
Name = "Tebet Eco Park",
Region = "Jakarta Selatan",
Area = "15.3 Ha",
FloraCount = 45,
FaunaCount = 20,
Image = "loc-tebet.jpg"
},
new()
{
Slug = "hutan-kota-srengseng",
Name = "Hutan Kota Srengseng",
Image = "loc-srengseng.jpg",
Region = "Jakarta Barat",
Area = "15.3 Ha",
FloraCount = 45,
FaunaCount = 20
},
new()
{
Slug = "mangrove-angke",
Name = "Hutan Mangrove Angke",
Region = "Jakarta Barat",
Area = "15.3 Ha",
FloraCount = 45,
FaunaCount = 20,
Image = "loc-mangrove-pik.jpg"
}
}
};
return View(model);

View File

@ -1,12 +1,30 @@
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using kehati.Models.View;
using kehati.Database;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
namespace kehati.Controllers
{
public class LokasiController : Controller
{
public IActionResult Index()
private readonly ApplicationDbContext db;
public LokasiController(ApplicationDbContext context)
{
db = context;
}
public async Task<IActionResult> Index(int page = 1)
{
ViewBag.lokasiHome = await Pagination.PaginateAsync(
db.Lokasi.OrderByDescending(l => l.MsLokasiId),
page,12);
// ViewBag.lokasiHome = await db.Lokasi
// .OrderByDescending(l => l.MsLokasiId)
// .Take(12)
// .ToListAsync();
var model = new HomeViewModel
{
FeaturedLocations = new List<LokasiModel>

View File

@ -0,0 +1,26 @@
using kehati.Models.Common;
using Microsoft.EntityFrameworkCore;
public static class Pagination
{
public static async Task<PagedResult<T>> PaginateAsync<T>(
IQueryable<T> query,
int page = 1,
int pageSize = 10)
{
var totalItems = await query.CountAsync();
var items = await query
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
return new PagedResult<T>
{
Items = items,
CurrentPage = page,
PageSize = pageSize,
TotalItems = totalItems
};
}
}

View File

@ -0,0 +1,19 @@
namespace kehati.Models.Common;
using Microsoft.EntityFrameworkCore;
public class PagedResult<T>
{
public List<T> Items { get; set; } = new();
public int CurrentPage { get; set; }
public int PageSize { get; set; }
public int TotalItems { get; set; }
public int TotalPages => (int)Math.Ceiling((double)TotalItems / PageSize);
public bool HasPrevious => CurrentPage > 1;
public bool HasNext => CurrentPage < TotalPages;
}

View File

@ -251,7 +251,7 @@
<div class="p-4">
<div class="flex items-start justify-between gap-2">
<h3 class="font-serif text-lg leading-tight text-foreground">
@s.NamaIlmiah
@s.Name
</h3>
</div>
<p class="mt-0.5 text-xs italic text-muted-foreground">
@ -329,7 +329,7 @@
<div class="p-4">
<div class="flex items-start justify-between gap-2">
<h3 class="font-serif text-lg leading-tight text-foreground">
@s.NamaIlmiah
@s.Name
</h3>
</div>
<p class="mt-0.5 text-xs italic text-muted-foreground">

View File

@ -1,6 +1,10 @@
@using kehati.Models.View
@using kehati.Models.Entity.Master
@using kehati.Models.Common
@{
ViewData["Title"] = "Lokasi";
var lokasi = ViewBag.LokasiHome as PagedResult<Lokasi>;
}
<section class="mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:px-8">
@ -17,51 +21,57 @@
</p>
</div>
<div class="mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
@foreach(LokasiModel loc in Model.FeaturedLocations)
@if (lokasi != null)
{
<a asp-controller="lokasi"
asp-action="detail"
asp-route-slug="@loc.Slug"
class="group block overflow-hidden rounded-2xl border border-border bg-card transition-all hover:-translate-y-1 hover:shadow-lg">
<!-- Image -->
<div class="relative aspect-[16/10] overflow-hidden bg-muted">
<img src="~/images/@loc.Image"
alt="@loc.Name"
loading="lazy"
asp-append-version="true"
class="h-full w-full object-cover transition-transform duration-500 group-hover:scale-105" />
<!-- Gradient -->
<div class="absolute inset-0 bg-gradient-to-t from-black/60 via-black/10 to-transparent"></div>
<!-- Overlay Text -->
<div class="absolute inset-x-0 bottom-0 p-4 text-white">
<div class="flex items-center gap-1.5 text-[11px] uppercase tracking-wider text-white/80">
<i data-lucide="map-pin" class="h-3 w-3"></i>
@loc.Region
@foreach (Lokasi loc in lokasi.Items)
{
<a asp-controller="lokasi"
asp-action="detail"
asp-route-slug="@loc.Slug"
class="group block overflow-hidden rounded-2xl border border-border bg-card transition-all hover:-translate-y-1 hover:shadow-lg">
<!-- Image -->
<div class="relative aspect-[16/10] overflow-hidden bg-muted">
<img src="~/images/@loc.Image"
alt="@loc.Name"
loading="lazy"
asp-append-version="true"
class="h-full w-full object-cover transition-transform duration-500 group-hover:scale-105" />
<!-- Gradient -->
<div class="absolute inset-0 bg-gradient-to-t from-black/60 via-black/10 to-transparent"></div>
<!-- Overlay Text -->
<div class="absolute inset-x-0 bottom-0 p-4 text-white">
<div class="flex items-center gap-1.5 text-[11px] uppercase tracking-wider text-white/80">
<i data-lucide="map-pin" class="h-3 w-3"></i>
@loc.Region
</div>
<h3 class="mt-1 font-serif text-xl leading-tight">
@loc.Name
</h3>
</div>
<h3 class="mt-1 font-serif text-xl leading-tight">
@loc.Name
</h3>
</div>
</div>
<!-- Footer Card -->
<div class="flex items-center justify-between p-4 text-sm">
<span class="text-muted-foreground">
@loc.Area
</span>
<div class="flex gap-3 text-foreground">
<span class="flex items-center gap-1">
<i data-lucide="leaf"
class="h-4 w-4 text-primary"></i>
@loc.FloraCount Flora
</span>
<span class="flex items-center gap-1">
<i data-lucide="bird"
class="h-4 w-4 text-primary"></i>
@loc.FaunaCount Fauna
<!-- Footer Card -->
<div class="flex items-center justify-between p-4 text-sm">
<span class="text-muted-foreground">
@loc.Area
</span>
<div class="flex gap-3 text-foreground">
<span class="flex items-center gap-1">
<i data-lucide="leaf"
class="h-4 w-4 text-primary"></i>
12 Flora
</span>
<span class="flex items-center gap-1">
<i data-lucide="bird"
class="h-4 w-4 text-primary"></i>
13 Fauna
</span>
</div>
</div>
</div>
</a>
}
}else{
<h4>Data Tidak Ada</h4>
}
</div>
<partial name="_Pagination" model="lokasi" />
</section>

View File

@ -0,0 +1,43 @@
@model dynamic
<div class="mt-8">
@if (Model.TotalPages > 1)
{
<nav class="">
<ul class="pagination flex gap-1">
@if (Model.HasPrevious)
{
<li class="page-item p-3 border rounded bg-white">
<a class="page-link"
href="?page=@(Model.CurrentPage - 1)">
Previous
</a>
</li>
}
@for (int i = 1; i <= Model.TotalPages; i++)
{
<li class="page-item p-3 border rounded @(i == Model.CurrentPage ? "active bg-primary text-white" : "bg-white")">
<a class="page-link"
href="?page=@i">
@i
</a>
</li>
}
@if (Model.HasNext)
{
<li class="page-item p-3 border rounded bg-white">
<a class="page-link"
href="?page=@(Model.CurrentPage + 1)">
Next
</a>
</li>
}
</ul>
</nav>
}
</div>

Binary file not shown.

Binary file not shown.

View File

@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("kehati")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+540f387d483887329065c922f1bfe0998ea815e9")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d0e1e97254bde87a49d930b41ab395484eaf1ebd")]
[assembly: System.Reflection.AssemblyProductAttribute("kehati")]
[assembly: System.Reflection.AssemblyTitleAttribute("kehati")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@ -1 +1 @@
bf306351a50bc8540eaf5629d2146b5ced3ec637053ff918a9c191fef6da2d2b
e52c76e3c84dafd7c8277601030ff7af613273bff9e4fdceb617a3e35c2080b3

View File

@ -84,6 +84,10 @@ build_metadata.AdditionalFiles.CssScope =
build_metadata.AdditionalFiles.TargetPath = Vmlld3MvU2hhcmVkL19BdXRoTGF5b3V0LmNzaHRtbA==
build_metadata.AdditionalFiles.CssScope =
[/Applications/MAMP/htdocs/kehati/Views/Shared/_Pagination.cshtml]
build_metadata.AdditionalFiles.TargetPath = Vmlld3MvU2hhcmVkL19QYWdpbmF0aW9uLmNzaHRtbA==
build_metadata.AdditionalFiles.CssScope =
[/Applications/MAMP/htdocs/kehati/Views/Shared/_ValidationScriptsPartial.cshtml]
build_metadata.AdditionalFiles.TargetPath = Vmlld3MvU2hhcmVkL19WYWxpZGF0aW9uU2NyaXB0c1BhcnRpYWwuY3NodG1s
build_metadata.AdditionalFiles.CssScope =

View File

@ -1 +1 @@
1f059a0dfdc5dad7c961ca427baf2ab8eba47c8ba6107dbbb3f18481ff330543
3c47bf4ab7b38e3a0eb2f760261c7bb595133e0d70d143ddbd06f1d167e6b215

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3,6 +3,8 @@
"version": "1.0.0",
"main": "index.js",
"scripts": {
"dev": "tailwindcss -i ./wwwroot/css/app.css -o ./wwwroot/css/site.css --watch",
"build": "tailwindcss -i ./wwwroot/css/app.css -o ./wwwroot/css/output.css --minify",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],

File diff suppressed because it is too large Load Diff