feat: add admin layout components including Navbar and Sidebar, and update icon components
This commit is contained in:
parent
47af75ebd3
commit
48ac1d6f4d
23
app/components/icons/cashier-machine.tsx
Normal file
23
app/components/icons/cashier-machine.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import type { JSX, SVGProps } from 'react'
|
||||
|
||||
export const CashierMachineIcon = (
|
||||
properties: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
|
||||
) => {
|
||||
return (
|
||||
<svg
|
||||
width={14}
|
||||
height={16}
|
||||
viewBox="0 0 14 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...properties}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M11.778 3.87h-1.553v-.988h1.268c.324 0 .586-.325.586-.723V.833c0-.4-.262-.723-.586-.723h-3.46c-.325 0-.586.324-.586.723V2.16c0 .4.26.723.585.723h1.292v.989H3.07a.628.628 0 00-.629.626L.876 12.59v2.521H14v-2.52l-1.593-8.093a.628.628 0 00-.63-.626zm-7.15 7.505h-.966v-.982h.967v.982zM3.662 9.5v-.982h.967V9.5H3.66zm2.843 1.89h-.967v-.997h.967v.996zm0-1.905h-.982v-.953h.982v.953zm1.875 1.902h-.982v-.994h.982v.994zm-.982-1.902v-.967h.982v.967h-.982zM8.38 7.61H3.662V5.735H8.38V7.61zm2.798 0H9.285v-.956h1.892v.956z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
23
app/components/icons/chart.tsx
Normal file
23
app/components/icons/chart.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import type { JSX, SVGProps } from 'react'
|
||||
|
||||
export const ChartIcon = (
|
||||
properties: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
|
||||
) => {
|
||||
return (
|
||||
<svg
|
||||
width={18}
|
||||
height={19}
|
||||
viewBox="0 0 18 19"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...properties}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M5.498 1.61h7.004c2.55 0 3.99 1.447 3.998 3.998v7.005c0 2.55-1.447 3.997-3.998 3.997H5.498c-2.551 0-3.998-1.447-3.998-3.997V5.608c0-2.55 1.447-3.998 3.998-3.998zm3.539 11.895a.62.62 0 00.623-.562V5.3a.612.612 0 00-.285-.592.63.63 0 00-.96.592v7.643a.632.632 0 00.622.562zm3.45 0c.316 0 .585-.24.623-.562v-2.46a.629.629 0 00-.96-.593.604.604 0 00-.285.593v2.46c.03.322.3.562.623.562zm-6.322-.562a.62.62 0 01-.623.562.62.62 0 01-.622-.562V7.76a.63.63 0 01.293-.592.617.617 0 01.66 0c.202.127.315.36.292.592v5.183z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
23
app/components/icons/chat.tsx
Normal file
23
app/components/icons/chat.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import type { JSX, SVGProps } from 'react'
|
||||
|
||||
export const ChatIcon = (
|
||||
properties: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
|
||||
) => {
|
||||
return (
|
||||
<svg
|
||||
width={18}
|
||||
height={19}
|
||||
viewBox="0 0 18 19"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...properties}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M1.5 9.122C1.5 5.17 4.657 1.61 9.015 1.61c4.26 0 7.485 3.493 7.485 7.49 0 4.633-3.78 7.51-7.5 7.51-1.23 0-2.595-.33-3.69-.976-.382-.233-.705-.406-1.117-.27l-1.515.45c-.383.12-.728-.18-.615-.586l.502-1.682a.786.786 0 00-.052-.676C1.868 11.683 1.5 10.384 1.5 9.122zm6.525 0c0 .533.427.961.96.969a.963.963 0 000-1.923.956.956 0 00-.96.954zm3.457.007c0 .526.428.962.96.962a.963.963 0 000-1.923.958.958 0 00-.96.961zm-5.954.962a.967.967 0 01-.96-.962c0-.533.427-.961.96-.961.532 0 .96.428.96.961a.967.967 0 01-.96.962z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@ -16,7 +16,7 @@ export const CloseIcon = (
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M20 23.537l8.838 8.838a2.5 2.5 0 003.537-3.537L23.533 20l8.84-8.838a2.498 2.498 0 000-3.536 2.5 2.5 0 00-3.536 0L20 16.466l-8.838-8.838a2.5 2.5 0 10-3.537 3.533L16.467 20l-8.84 8.84a2.5 2.5 0 103.536 3.533L20 23.537z"
|
||||
fill="#currentColor"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
23
app/components/icons/document.tsx
Normal file
23
app/components/icons/document.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import type { JSX, SVGProps } from 'react'
|
||||
|
||||
export const DocumentIcon = (
|
||||
properties: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
|
||||
) => {
|
||||
return (
|
||||
<svg
|
||||
width={18}
|
||||
height={19}
|
||||
viewBox="0 0 18 19"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...properties}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M5.857 1.61h6.286c2.317 0 3.607 1.335 3.607 3.623v7.747c0 2.325-1.29 3.63-3.607 3.63H5.857c-2.28 0-3.607-1.305-3.607-3.63V5.233c0-2.288 1.328-3.623 3.607-3.623zm.203 3.495v-.007h2.242a.588.588 0 010 1.178H6.06a.585.585 0 010-1.17zm0 4.56h5.88a.586.586 0 000-1.17H6.06a.586.586 0 000 1.17zm0 3.428h5.88c.3-.03.525-.286.525-.585a.588.588 0 00-.525-.593H6.06a.596.596 0 00-.563.908c.12.187.338.3.563.27z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@ -8,13 +8,13 @@ export const EyeIcon = (
|
||||
width={28}
|
||||
height={20}
|
||||
viewBox="0 0 28 20"
|
||||
fill="currentColor"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...properties}
|
||||
>
|
||||
<path
|
||||
d="M14 .676C3.823.676.764 9.49.736 9.58L.595 10l.14.422c.03.09 3.088 8.903 13.265 8.903s13.236-8.814 13.264-8.903l.141-.421-.14-.42C27.236 9.49 24.177.675 14 .675zm0 14.652A5.336 5.336 0 018.667 10 5.336 5.336 0 0114 4.672 5.336 5.336 0 0119.333 10 5.336 5.336 0 0114 15.328z"
|
||||
fill="#currentColor"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
21
app/components/icons/medical-notes.tsx
Normal file
21
app/components/icons/medical-notes.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import type { JSX, SVGProps } from 'react'
|
||||
|
||||
export const MedicalNotesIcon = (
|
||||
properties: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
|
||||
) => {
|
||||
return (
|
||||
<svg
|
||||
width={12}
|
||||
height={16}
|
||||
viewBox="0 0 12 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...properties}
|
||||
>
|
||||
<path
|
||||
d="M9.844 1.985H7.5C7.5.951 6.66.11 5.625.11 4.591.11 3.75.951 3.75 1.985H1.406C.63 1.985 0 2.615 0 3.392v10.312c0 .776.63 1.406 1.406 1.406h8.438c.776 0 1.406-.63 1.406-1.406V3.392c0-.777-.63-1.407-1.406-1.407zm-4.219-.703c.39 0 .703.314.703.703 0 .39-.313.703-.703.703a.701.701 0 01-.703-.703c0-.39.313-.703.703-.703zm2.813 8.906a.235.235 0 01-.235.235h-1.64v1.64a.235.235 0 01-.235.235H4.922a.235.235 0 01-.234-.235v-1.64H3.046a.235.235 0 01-.235-.235V8.782c0-.129.106-.234.235-.234h1.64v-1.64c0-.13.106-.235.235-.235h1.406c.129 0 .234.105.234.234v1.64h1.641c.129 0 .235.106.235.235v1.406zm0-5.625a.235.235 0 01-.235.235H3.047a.235.235 0 01-.235-.235v-.468c0-.13.106-.235.235-.235h5.156c.129 0 .235.106.235.235v.468z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
23
app/components/icons/profile.tsx
Normal file
23
app/components/icons/profile.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import type { JSX, SVGProps } from 'react'
|
||||
|
||||
export const ProfileIcon = (
|
||||
properties: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
|
||||
) => {
|
||||
return (
|
||||
<svg
|
||||
width={18}
|
||||
height={19}
|
||||
viewBox="0 0 18 19"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...properties}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M12.97 5.82A3.956 3.956 0 019 9.789a3.956 3.956 0 01-3.97-3.97A3.955 3.955 0 019 1.853a3.955 3.955 0 013.97 3.968zM9 16.852c-3.253 0-6-.53-6-2.57s2.764-2.55 6-2.55c3.254 0 6 .529 6 2.569s-2.764 2.55-6 2.55z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
23
app/components/icons/setting.tsx
Normal file
23
app/components/icons/setting.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import type { JSX, SVGProps } from 'react'
|
||||
|
||||
export const SettingIcon = (
|
||||
properties: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
|
||||
) => {
|
||||
return (
|
||||
<svg
|
||||
width={18}
|
||||
height={19}
|
||||
viewBox="0 0 18 19"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...properties}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M15.302 10.537c.268.142.475.367.62.592.284.465.261 1.035-.015 1.538l-.537.9c-.283.48-.812.78-1.356.78a1.6 1.6 0 01-.813-.225c-.199-.128-.429-.173-.674-.173-.759 0-1.395.623-1.418 1.365 0 .863-.705 1.538-1.587 1.538H8.48c-.89 0-1.594-.675-1.594-1.538-.016-.742-.652-1.365-1.41-1.365-.254 0-.483.045-.675.173a1.62 1.62 0 01-.813.225 1.6 1.6 0 01-1.364-.78l-.529-.9c-.283-.488-.299-1.073-.015-1.538.123-.225.353-.45.613-.592.215-.105.353-.278.483-.48.383-.645.153-1.493-.498-1.875a1.533 1.533 0 01-.567-2.123l.513-.885a1.593 1.593 0 012.162-.57c.666.36 1.533.12 1.923-.517a1.16 1.16 0 00.177-.66c-.016-.293.069-.57.214-.795a1.646 1.646 0 011.357-.78h1.08c.568 0 1.081.315 1.365.78.138.225.23.502.207.795-.015.225.054.45.176.66a1.48 1.48 0 001.932.517 1.584 1.584 0 012.153.57l.514.885a1.52 1.52 0 01-.567 2.123c-.652.382-.882 1.23-.49 1.875.122.202.26.375.475.48zm-8.47-1.178c0 1.178.973 2.115 2.177 2.115 1.203 0 2.153-.937 2.153-2.115 0-1.177-.95-2.122-2.153-2.122-1.204 0-2.177.945-2.177 2.122z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
23
app/components/icons/wallet.tsx
Normal file
23
app/components/icons/wallet.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import type { JSX, SVGProps } from 'react'
|
||||
|
||||
export const WalletIcon = (
|
||||
properties: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
|
||||
) => {
|
||||
return (
|
||||
<svg
|
||||
width={18}
|
||||
height={19}
|
||||
viewBox="0 0 18 19"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...properties}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M13.327 6.638H16.5c0-2.548-1.527-4.036-4.113-4.036H5.613C3.027 2.602 1.5 4.09 1.5 6.605v5.493c0 2.515 1.527 4.004 4.113 4.004h6.774c2.586 0 4.113-1.489 4.113-4.004v-.234h-3.173c-1.473 0-2.667-1.164-2.667-2.6 0-1.436 1.194-2.6 2.667-2.6v-.026zm0 1.118h2.613c.31 0 .56.244.56.546V10.2a.56.56 0 01-.56.546h-2.553A1.58 1.58 0 0111.82 9.55c-.085-.44.034-.893.325-1.24.29-.345.723-.548 1.181-.554zm.113 1.995h.247c.316 0 .573-.25.573-.559a.566.566 0 00-.573-.559h-.247a.574.574 0 00-.405.16.545.545 0 00-.168.393c0 .31.255.562.573.565zM5.053 6.638h4.234c.316 0 .573-.25.573-.56a.566.566 0 00-.573-.558H5.053a.567.567 0 00-.573.552c0 .31.256.562.573.566z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@ -1,12 +1,15 @@
|
||||
import type { PropsWithChildren } from 'react'
|
||||
|
||||
import { Navbar } from './navbar'
|
||||
import { Sidebar } from './sidebar'
|
||||
|
||||
export const AdminDashboardLayout = (properties: PropsWithChildren) => {
|
||||
const { children } = properties
|
||||
return (
|
||||
<div className="grid">
|
||||
<div>Navbar</div>
|
||||
<Navbar />
|
||||
<div className="flex">
|
||||
<div>Sidebar</div>
|
||||
<Sidebar />
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
73
app/layouts/admin/menu.ts
Normal file
73
app/layouts/admin/menu.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import type { JSX, SVGProps } from 'react'
|
||||
|
||||
import { ChartIcon } from '~/components/icons/chart'
|
||||
import { ChatIcon } from '~/components/icons/chat'
|
||||
import { DocumentIcon } from '~/components/icons/document'
|
||||
import { MedicalNotesIcon } from '~/components/icons/medical-notes'
|
||||
import { ProfileIcon } from '~/components/icons/profile'
|
||||
import { SettingIcon } from '~/components/icons/setting'
|
||||
import { WalletIcon } from '~/components/icons/wallet'
|
||||
|
||||
type TMenu = {
|
||||
group: string
|
||||
items: {
|
||||
title: string
|
||||
url: string
|
||||
icon: (
|
||||
properties: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
|
||||
) => JSX.Element
|
||||
}[]
|
||||
}
|
||||
|
||||
export const MENU: TMenu[] = [
|
||||
{
|
||||
group: 'Menu',
|
||||
items: [
|
||||
{
|
||||
title: 'Dashboard',
|
||||
url: '/admin/dashboard',
|
||||
icon: ChartIcon,
|
||||
},
|
||||
{
|
||||
title: 'User',
|
||||
url: '/admin/dashboard/users',
|
||||
icon: DocumentIcon,
|
||||
},
|
||||
{
|
||||
title: 'Konten',
|
||||
url: '/admin/dashboard/contents',
|
||||
icon: ChatIcon,
|
||||
},
|
||||
{
|
||||
title: 'Advertisement',
|
||||
url: '/admin/dashboard/advertisements',
|
||||
icon: MedicalNotesIcon,
|
||||
},
|
||||
{
|
||||
title: 'Subscription',
|
||||
url: '/admin/dashboard/subscriptions',
|
||||
icon: ChartIcon,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
group: 'Others',
|
||||
items: [
|
||||
{
|
||||
title: 'Data Situs',
|
||||
url: '/admin/dashboard/site-data',
|
||||
icon: WalletIcon,
|
||||
},
|
||||
{
|
||||
title: 'Pengaturan',
|
||||
url: '/admin/dashboard/settings',
|
||||
icon: SettingIcon,
|
||||
},
|
||||
{
|
||||
title: 'Admin',
|
||||
url: '/admin/dashboard/admins',
|
||||
icon: ProfileIcon,
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
3
app/layouts/admin/navbar.tsx
Normal file
3
app/layouts/admin/navbar.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
export const Navbar = () => {
|
||||
return <div>Navbar</div>
|
||||
}
|
||||
25
app/layouts/admin/sidebar.tsx
Normal file
25
app/layouts/admin/sidebar.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import { Link } from 'react-router'
|
||||
|
||||
import { MENU } from './menu'
|
||||
|
||||
export const Sidebar = () => {
|
||||
return (
|
||||
<div>
|
||||
{MENU.map(({ group, items }) => (
|
||||
<>
|
||||
<div key={group}>{group}</div>
|
||||
{items.map(({ title, url, icon: Icon }) => (
|
||||
<Link
|
||||
to={url}
|
||||
key={`${group}-${title}`}
|
||||
className="flex items-center gap-x-3 text-[#273240]"
|
||||
>
|
||||
<Icon className="h-[18px] w-[18px] text-[#A6ABC8]" />
|
||||
<span>{title}</span>
|
||||
</Link>
|
||||
))}
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -5,7 +5,20 @@ import { InstagramIcon } from '~/components/icons/instagram'
|
||||
import { LinkedinIcon } from '~/components/icons/linkedin'
|
||||
import { XIcon } from '~/components/icons/x'
|
||||
|
||||
export const MENU = [
|
||||
type TMenu = {
|
||||
title: string
|
||||
url: string
|
||||
icon?: (
|
||||
properties: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
|
||||
) => JSX.Element
|
||||
}
|
||||
|
||||
type TFooterMenu = {
|
||||
group: string
|
||||
items: TMenu[]
|
||||
}
|
||||
|
||||
export const MENU: TMenu[] = [
|
||||
{
|
||||
title: 'Spotlight',
|
||||
url: '/news/category/spotlight',
|
||||
@ -36,17 +49,7 @@ export const MENU = [
|
||||
},
|
||||
]
|
||||
|
||||
type FooterMenu = {
|
||||
group: string
|
||||
items: Array<{
|
||||
title: string
|
||||
url: string
|
||||
icon?: (
|
||||
properties: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
|
||||
) => JSX.Element
|
||||
}>
|
||||
}
|
||||
export const FOOTER_MENU: FooterMenu[] = [
|
||||
export const FOOTER_MENU: TFooterMenu[] = [
|
||||
{
|
||||
group: 'About Us',
|
||||
items: [
|
||||
@ -124,7 +127,7 @@ export const FOOTER_MENU: FooterMenu[] = [
|
||||
},
|
||||
]
|
||||
|
||||
export const COPYRIGHT_MENU = [
|
||||
export const COPYRIGHT_MENU: TMenu[] = [
|
||||
{
|
||||
title: 'Privacy Policy',
|
||||
url: '/news/privacy-policy',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user