From 8b1af335eca48613493c00014e8334486f8f89c5 Mon Sep 17 00:00:00 2001 From: Ardeman Date: Sun, 23 Feb 2025 10:11:47 +0800 Subject: [PATCH] feat: add admin and dashboard layouts with context for improved structure and functionality --- app/app.css | 4 + app/contexts/admin.tsx | 41 +++++++ app/contexts/news.tsx | 8 +- app/layouts/admin/default.tsx | 10 ++ app/layouts/news/menu.ts | 4 +- app/root.tsx | 7 +- app/routes/_layout.admin.auth.login.tsx | 106 ++++++++++++++++++ ....login.tsx => _layout.admin.dashboard.tsx} | 4 +- app/routes/_layout.admin.tsx | 16 +++ app/routes/_layout.dashboard.tsx | 5 - 10 files changed, 188 insertions(+), 17 deletions(-) create mode 100644 app/contexts/admin.tsx create mode 100644 app/layouts/admin/default.tsx create mode 100644 app/routes/_layout.admin.auth.login.tsx rename app/routes/{_layout.dashboard.auth.login.tsx => _layout.admin.dashboard.tsx} (73%) create mode 100644 app/routes/_layout.admin.tsx delete mode 100644 app/routes/_layout.dashboard.tsx diff --git a/app/app.css b/app/app.css index 2e73e05..f353a4a 100644 --- a/app/app.css +++ b/app/app.css @@ -1,9 +1,13 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap'); @import 'tailwindcss'; @plugin "@tailwindcss/typography"; @theme { --font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + --font-admin: 'Poppins', ui-sans-serif, system-ui, sans-serif, + 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; } html, diff --git a/app/contexts/admin.tsx b/app/contexts/admin.tsx new file mode 100644 index 0000000..364248f --- /dev/null +++ b/app/contexts/admin.tsx @@ -0,0 +1,41 @@ +import { + createContext, + useState, + useContext, + type PropsWithChildren, + type SetStateAction, + type Dispatch, +} from 'react' + +type AdminProfile = { + name: string +} + +type AdminContextProperties = { + adminProfile: AdminProfile + setAdminProfile: Dispatch> +} + +const AdminContext = createContext( + undefined, +) + +export const AdminProvider = ({ children }: PropsWithChildren) => { + const [adminProfile, setAdminProfile] = useState({ + name: '', + }) + + return ( + + {children} + + ) +} + +export const useAdminContext = (): AdminContextProperties => { + const context = useContext(AdminContext) + if (!context) { + throw new Error('useAdminContext must be used within a AdminProvider') + } + return context +} diff --git a/app/contexts/news.tsx b/app/contexts/news.tsx index d023b84..e338fe1 100644 --- a/app/contexts/news.tsx +++ b/app/contexts/news.tsx @@ -1,15 +1,17 @@ -import React, { +import { createContext, useState, useContext, type PropsWithChildren, + type Dispatch, + type SetStateAction, } from 'react' type NewsContextProperties = { isLoginOpen: boolean - setIsLoginOpen: React.Dispatch> + setIsLoginOpen: Dispatch> isRegisterOpen: boolean - setIsRegisterOpen: React.Dispatch> + setIsRegisterOpen: Dispatch> } const NewsContext = createContext(undefined) diff --git a/app/layouts/admin/default.tsx b/app/layouts/admin/default.tsx new file mode 100644 index 0000000..bbc9b5a --- /dev/null +++ b/app/layouts/admin/default.tsx @@ -0,0 +1,10 @@ +import type { PropsWithChildren } from 'react' + +export const AdminDefaultLayout = (properties: PropsWithChildren) => { + const { children } = properties + return ( +
+ {children} +
+ ) +} diff --git a/app/layouts/news/menu.ts b/app/layouts/news/menu.ts index 715d445..d042c14 100644 --- a/app/layouts/news/menu.ts +++ b/app/layouts/news/menu.ts @@ -1,4 +1,4 @@ -import type { JSX } from 'react' +import type { JSX, SVGProps } from 'react' import { FacebookIcon } from '~/components/icons/facebook' import { InstagramIcon } from '~/components/icons/instagram' @@ -42,7 +42,7 @@ type FooterMenu = { title: string url: string icon?: ( - properties: JSX.IntrinsicAttributes & React.SVGProps, + properties: JSX.IntrinsicAttributes & SVGProps, ) => JSX.Element }> } diff --git a/app/root.tsx b/app/root.tsx index 294e404..d012220 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -1,3 +1,4 @@ +import type { ReactNode } from 'react' import { isRouteErrorResponse, Links, @@ -18,10 +19,6 @@ export const links: Route.LinksFunction = () => [ href: 'https://fonts.gstatic.com', crossOrigin: 'anonymous', }, - { - rel: 'stylesheet', - href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap', - }, ] export const meta = ({ location }: Route.MetaArgs) => { @@ -39,7 +36,7 @@ export const meta = ({ location }: Route.MetaArgs) => { ] } -export function Layout({ children }: { children: React.ReactNode }) { +export function Layout({ children }: { children: ReactNode }) { return ( diff --git a/app/routes/_layout.admin.auth.login.tsx b/app/routes/_layout.admin.auth.login.tsx new file mode 100644 index 0000000..2726d17 --- /dev/null +++ b/app/routes/_layout.admin.auth.login.tsx @@ -0,0 +1,106 @@ +import { useState } from 'react' +import { Link } from 'react-router' + +import { EyeIcon } from '~/components/icons/eye' +import { Button } from '~/components/ui/button' +import { APP } from '~/data/meta' + +const AuthLayout = () => { + const [showPassword, setShowPassword] = useState(false) + + return ( +
+
+
+ {APP.title} +
+

+ Selamat Datang, silakan masukkan akun Anda untuk melanjutkan! +

+
+
+ {/* Input Email / No Telepon */} +
+ + +
+ + {/* Input Password */} +
+ + + +
+ + {/* Lupa Kata Sandi */} +
+ Lupa Kata Sandi? + + Reset Kata Sandi + +
+ + {/* Tombol Masuk */} + +
+
+
+ {/* Link Daftar */} +
+ Belum punya akun?{' '} + +
+
+ ) +} +export default AuthLayout diff --git a/app/routes/_layout.dashboard.auth.login.tsx b/app/routes/_layout.admin.dashboard.tsx similarity index 73% rename from app/routes/_layout.dashboard.auth.login.tsx rename to app/routes/_layout.admin.dashboard.tsx index d67b1bb..d71ad97 100644 --- a/app/routes/_layout.dashboard.auth.login.tsx +++ b/app/routes/_layout.admin.dashboard.tsx @@ -1,4 +1,4 @@ -const AuthLayout = () => { +const DashboardLayout = () => { return (
@@ -7,4 +7,4 @@ const AuthLayout = () => {
) } -export default AuthLayout +export default DashboardLayout diff --git a/app/routes/_layout.admin.tsx b/app/routes/_layout.admin.tsx new file mode 100644 index 0000000..565ed09 --- /dev/null +++ b/app/routes/_layout.admin.tsx @@ -0,0 +1,16 @@ +import { Outlet } from 'react-router' + +import { AdminProvider } from '~/contexts/admin' +import { AdminDefaultLayout } from '~/layouts/admin/default' + +const AdminLayout = () => { + return ( + + + + + + ) +} + +export default AdminLayout diff --git a/app/routes/_layout.dashboard.tsx b/app/routes/_layout.dashboard.tsx deleted file mode 100644 index b8f0bc5..0000000 --- a/app/routes/_layout.dashboard.tsx +++ /dev/null @@ -1,5 +0,0 @@ -const DashboardLayout = () => { - return
Dashboard
-} - -export default DashboardLayout