Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Know Nepal</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Space+Grotesk:wght@400;500;600;700&display=swap" rel="stylesheet" />
</head>
<body>
<div id="root"></div>
Expand Down
15 changes: 6 additions & 9 deletions src/components/app/footer.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
/**
*
*/
export default function AppFooter() {
return (
<footer className="px-2 py-5 md:p-10">
<div className="mb-5 w-full border-b border-gray-300" />

<p className="text-center">
© {new Date().getFullYear()} Know Nepal. All rights reserved.
</p>
<footer className="border-t border-white/5 px-4 py-8 md:px-8">
<div className="mx-auto max-w-7xl">
<p className="text-center text-sm text-gray-600">
© {new Date().getFullYear()} Know Nepal. All rights reserved.
</p>
</div>
</footer>
);
}
51 changes: 31 additions & 20 deletions src/components/app/navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,39 @@
import { Link } from "react-router-dom";
import { Link, useLocation } from "react-router-dom";

const navLinks = [
{ to: "/tech-companies", label: "Tech Companies" },
{ to: "/government-websites", label: "Government Websites" },
];

/**
*
*/
export default function AppNavbar() {
return (
<nav className="flex justify-between px-2 py-7 md:px-10">
<Link to="/" className="font-sans text-xl uppercase">
<div className="flex items-center">
<img src="/knowNepalLogo.png" alt="" className="mr-2 h-8 w-8" />
Know Nepal
</div>
</Link>
const { pathname } = useLocation();

<div className="flex gap-x-5">
<Link to="/tech-companies" className="group">
<p>Tech Companies</p>
<div className="mt-[2px] w-0 border-b-2 border-highlight transition-all duration-300 group-hover:w-full" />
return (
<nav className="sticky top-0 z-50 border-b border-white/5 bg-[#0F0913]/90 backdrop-blur-xl">
<div className="mx-auto flex max-w-7xl items-center justify-between px-4 py-4 md:px-8">
<Link
to="/"
className="flex items-center gap-2.5 font-display text-lg font-semibold tracking-tight"
>
<img src="/knowNepalLogo.png" alt="Know Nepal" className="h-8 w-8" />
<span>Know Nepal</span>
</Link>

<Link to="/government-websites" className="group">
<p>Government Websites</p>
<div className="mt-[2px] w-0 border-b-2 border-highlight transition-all duration-300 group-hover:w-full" />
</Link>
<div className="flex items-center gap-1">
{navLinks.map(({ to, label }) => (
<Link
key={to}
to={to}
className={`rounded-lg px-4 py-2 text-sm font-medium transition-all duration-200 ${
pathname === to
? "bg-primary-300/40 text-primary-100"
: "text-gray-400 hover:bg-white/5 hover:text-gray-100"
}`}
>
{label}
</Link>
))}
</div>
</div>
</nav>
);
Expand Down
24 changes: 22 additions & 2 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@
@tailwind components;
@tailwind utilities;

body {
@apply bg-[#0F0913] text-[#EFEDEF];
@layer base {
body {
@apply bg-[#0F0913] font-sans text-[#EFEDEF] antialiased;
}
}

@layer components {
.card {
@apply rounded-xl border border-white/5 bg-primary-400 p-5 shadow-card transition-all duration-300 hover:scale-[1.01] hover:border-primary-200/20 hover:shadow-card-hover;
}

.search-input {
@apply w-full max-w-lg rounded-full border border-white/10 bg-white/5 px-5 py-3 text-gray-200 placeholder:text-gray-500 transition-all duration-200 focus:border-primary-200/30 focus:bg-white/10 focus:outline-none focus:ring-2 focus:ring-primary-200/20;
}

.btn-highlight {
@apply inline-flex items-center rounded-full bg-highlight px-5 py-2.5 text-sm font-semibold text-gray-900 transition-all duration-200 hover:scale-105 hover:bg-yellow-300 active:scale-95;
}

.btn-outline {
@apply inline-flex items-center rounded-full border border-white/10 px-5 py-2.5 text-sm font-medium text-gray-300 transition-all duration-200 hover:border-white/20 hover:text-white;
}
}
16 changes: 6 additions & 10 deletions src/layouts/default.layout.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import { Outlet } from "react-router-dom";

//
import AppNavbar from "../components/app/navbar";
import AppFooter from "../components/app/footer";

/**
*
*/
export default function DefaultLayout() {
return (
<div className="flex h-screen flex-col overflow-y-auto overflow-x-hidden">
<div className="flex min-h-screen flex-col overflow-x-hidden">
<AppNavbar />

<section className="flex-grow px-2 md:px-10">
<Outlet />
</section>

<main className="flex-grow">
<div className="mx-auto max-w-7xl px-4 md:px-8">
<Outlet />
</div>
</main>
<AppFooter />
</div>
);
Expand Down
188 changes: 141 additions & 47 deletions src/pages/government-websites.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,53 @@
import { useQuery } from "@tanstack/react-query";
import { useState } from "react";
import { useMemo, useState } from "react";
import Fuse from "fuse.js";
//
import { HiSearch, HiExternalLink } from "react-icons/hi";

import { getGovernmentWebsites } from "../utils/apis";

/**
*
*/
function getCategory(name: string): string {
const n = name.toLowerCase();
if (n.includes("ministry") || n.includes("mantralaya")) return "Ministries";
if (
n.includes("municipality") ||
n.includes("metropolitan") ||
n.includes("rural municipality") ||
n.includes("sub-metropolitan")
)
return "Local Government";
if (n.includes("pradesh") || n.includes("province"))
return "Province Government";
if (n.includes("police") || n.includes("army") || n.includes("armed"))
return "Security & Defense";
if (n.includes("court") || n.includes("judiciary")) return "Judiciary";
if (
n.includes("university") ||
n.includes("education") ||
n.includes("college") ||
n.includes("school") ||
n.includes("institute") ||
n.includes("hospital") ||
n.includes("health")
)
return "Education & Health";
if (
n.includes("bank") ||
n.includes("finance") ||
n.includes("revenue") ||
n.includes("customs") ||
n.includes("tax")
)
return "Finance & Revenue";
if (
n.includes("commission") ||
n.includes("parliament") ||
n.includes("election") ||
n.includes("sansad")
)
return "Constitutional Bodies";
return "Other Bodies";
}

export default function GovernmentWebsitesPage() {
const { data } = useQuery({
queryKey: ["get-government-websites"],
Expand All @@ -17,70 +58,123 @@
});

const [searchQuery, setSearchQuery] = useState("");
const fuseOptions = {
keys: ["name"],
threshold: 0.3,
ignoreLocation: true,
};
const [activeCategory, setActiveCategory] = useState("All");

const allItems = data || [];

Check warning on line 63 in src/pages/government-websites.tsx

View workflow job for this annotation

GitHub Actions / Test and Build

The 'allItems' logical expression could make the dependencies of useMemo Hook (at line 77) change on every render. To fix this, wrap the initialization of 'allItems' in its own useMemo() Hook

Check warning on line 63 in src/pages/government-websites.tsx

View workflow job for this annotation

GitHub Actions / Test and Build

The 'allItems' logical expression could make the dependencies of useMemo Hook (at line 67) change on every render. To fix this, wrap the initialization of 'allItems' in its own useMemo() Hook

const fuse = new Fuse(data, fuseOptions);
const allCategories = useMemo(
() => [...new Set(allItems.map((item) => getCategory(item.name)))].sort(),
[allItems],
);

const fuse = useMemo(
() =>
new Fuse(allItems, {
keys: ["name"],
threshold: 0.3,
ignoreLocation: true,
}),
[allItems],
);

const searchWebsites = (query: string) => {
const results = fuse.search(query);
const filteredData = results.map((result) => result.item);
return filteredData;
};
const afterSearch = searchQuery
? fuse.search(searchQuery).map((r) => r.item)
: allItems;

const filteredData = searchQuery ? searchWebsites(searchQuery) : data || [];
const filteredData =
activeCategory === "All"
? afterSearch
: afterSearch.filter((item) => getCategory(item.name) === activeCategory);

return (
<div>
<p className="text-center text-3xl">Government Websites in Nepal</p>
<div className="my-10 flex justify-center">
<input
type="text"
placeholder="Search for government website..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="focus:ring-hightlght w-full max-w-lg rounded-sm bg-gray-800 px-3 py-2 text-gray-200 placeholder:text-gray-400 focus:outline-none focus:ring-1 focus:ring-highlight"
/>
<div className="py-10">
<div className="mb-10 text-center">
<h1 className="font-display text-4xl font-bold tracking-tight">
Government Websites in Nepal
</h1>
{filteredData.length > 0 && (
<p className="mt-2 text-sm text-gray-500">
{filteredData.length}{" "}
{searchQuery || activeCategory !== "All"
? "results found"
: "websites listed"}
</p>
)}
</div>

<div className="mt-10 grid grid-cols-1 gap-2 md:grid-cols-3 md:gap-5 lg:grid-cols-4 lg:gap-10">
<div className="flex justify-center">
<div className="relative w-full max-w-lg">
<HiSearch
size={18}
className="pointer-events-none absolute left-4 top-1/2 -translate-y-1/2 text-gray-500"
/>
<input
type="text"
aria-label="Search for government website"
placeholder="Search for government website..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="search-input pl-11"
/>
</div>
</div>

{/* Category tabs */}
<div className="mt-6 flex flex-wrap justify-center gap-2">
{["All", ...allCategories].map((cat) => (
<button
key={cat}
onClick={() => setActiveCategory(cat)}
className={`rounded-full border px-4 py-1.5 text-sm font-medium transition-all duration-200 ${
activeCategory === cat
? "border-primary-200/30 bg-primary-300/40 text-primary-100"
: "border-white/10 text-gray-500 hover:border-white/20 hover:text-gray-300"
}`}
>
{cat}
</button>
))}
</div>

<div className="mt-8 grid grid-cols-1 gap-4 md:grid-cols-3 lg:grid-cols-4">
{filteredData.map((govWebsite) => (
<div
key={govWebsite.name}
className="group col-span-1 flex flex-col justify-between rounded-sm bg-primary-400 p-3 transition-all duration-200 hover:scale-[1.02] hover:bg-primary-300"
className="card flex flex-col items-center justify-between text-center"
>
<div>
<div className="flex justify-center">
<div className="flex flex-col items-center">
<div className="overflow-hidden rounded-full ring-1 ring-white/10">
<img
src="/nepalLogo.png"
width={96}
height={96}
className="h-24 w-24 rounded-full object-cover"
alt={`${govWebsite.name} logo`}
width={80}
height={80}
className="h-20 w-20 object-cover"
/>
</div>

<p className="my-3 flex cursor-pointer justify-center text-center text-lg group-hover:underline">
<span className="mt-3 rounded-full border border-white/5 bg-white/5 px-2.5 py-0.5 text-xs text-gray-500">
{getCategory(govWebsite.name)}
</span>

<h2 className="mt-2 font-display text-base font-semibold">
{govWebsite.name}
</p>
</h2>

<p className="my-5 text-center text-sm">
<p className="mt-3 text-sm leading-relaxed text-gray-400">
{govWebsite.description}
</p>
</div>

<p className="mb-3 mt-10 text-center">
<a
href={govWebsite.url}
rel="noopener"
target="_blank"
className="rounded-sm bg-highlight px-3 py-2 text-gray-900"
>
Visit website
</a>
</p>
<a
href={govWebsite.url}
rel="noopener"
target="_blank"
className="btn-highlight mt-6"
>
Visit website
<HiExternalLink className="ml-1.5" size={14} />
</a>
</div>
))}
</div>
Expand Down
Loading
Loading