+
{children}
)
diff --git a/components/CardBox.tsx b/components/CardBox.tsx
index 5dc270e..1c58d76 100644
--- a/components/CardBox.tsx
+++ b/components/CardBox.tsx
@@ -3,29 +3,31 @@ import CardBoxComponentBody from './CardBoxComponentBody'
import CardBoxComponentFooter from './CardBoxComponentFooter'
type Props = {
- rounded?: string,
- flex?: string,
- className?: string,
- hasComponentLayout?: boolean,
- hasTable?: boolean,
- isForm?: boolean,
- isHoverable?: boolean,
- isModal?: boolean,
- children: ReactNode,
+ rounded?: string
+ flex?: string
+ className?: string
+ hasComponentLayout?: boolean
+ hasTable?: boolean
+ isForm?: boolean
+ isHoverable?: boolean
+ isModal?: boolean
+ children: ReactNode
footer?: ReactNode
+ onClick?: Function
}
export default function CardBox({
rounded = 'rounded-2xl',
flex = 'flex-col',
className = '',
- hasComponentLayout=false,
- hasTable=false,
- isForm=false,
- isHoverable=false,
- isModal=false,
+ hasComponentLayout = false,
+ hasTable = false,
+ isForm = false,
+ isHoverable = false,
+ isModal = false,
children,
footer,
+ onClick,
}: Props) {
const componentClass = [
'bg-white flex',
@@ -41,7 +43,7 @@ export default function CardBox({
return React.createElement(
isForm ? 'form' : 'div',
- { className: componentClass.join(' ') },
+ { className: componentClass.join(' '), onClick },
hasComponentLayout ? (
children
) : (
diff --git a/components/CardBoxClient.tsx b/components/CardBoxClient.tsx
new file mode 100644
index 0000000..0adfe22
--- /dev/null
+++ b/components/CardBoxClient.tsx
@@ -0,0 +1,50 @@
+import { mdiTrendingDown, mdiTrendingNeutral, mdiTrendingUp } from '@mdi/js'
+import React from 'react'
+import { Client, ColorKey } from '../interfaces'
+import BaseLevel from './BaseLevel'
+import CardBox from './CardBox'
+import PillTag from './PillTag'
+import UserAvatar from './UserAvatar'
+
+type Props = {
+ client: Client
+}
+
+const CardBoxClient = (props: Props) => {
+ const pillColor = () => {
+ if (props.client.progress >= 60) {
+ return 'success'
+ }
+ if (props.client.progress >= 40) {
+ return 'warning'
+ }
+
+ return 'danger'
+ }
+
+ const pillIcon = {
+ success: mdiTrendingUp,
+ warning: mdiTrendingNeutral,
+ danger: mdiTrendingDown,
+ }[pillColor()]
+
+ return (
+
+
+
+
+
+
{props.client.name}
+
+ {props.client.created} @ {props.client.login}
+
+
+
+
+
+
+
+ )
+}
+
+export default CardBoxClient
diff --git a/components/CardBoxComponentBody.tsx b/components/CardBoxComponentBody.tsx
index 583040c..0be6338 100644
--- a/components/CardBoxComponentBody.tsx
+++ b/components/CardBoxComponentBody.tsx
@@ -1,10 +1,10 @@
-import React, { ReactNode } from "react"
+import React, { ReactNode } from 'react'
type Props = {
- noPadding?: boolean,
+ noPadding?: boolean
children?: ReactNode
}
-export default function CardBoxComponentBody({ noPadding=false, children }: Props) {
+export default function CardBoxComponentBody({ noPadding = false, children }: Props) {
return
{children}
}
diff --git a/components/CardBoxComponentFooter.tsx b/components/CardBoxComponentFooter.tsx
index 0b7041e..ba07202 100644
--- a/components/CardBoxComponentFooter.tsx
+++ b/components/CardBoxComponentFooter.tsx
@@ -1,4 +1,4 @@
-import React, { ReactNode } from "react"
+import React, { ReactNode } from 'react'
type Props = {
children?: ReactNode
diff --git a/components/CardBoxTransaction.tsx b/components/CardBoxTransaction.tsx
new file mode 100644
index 0000000..53c2516
--- /dev/null
+++ b/components/CardBoxTransaction.tsx
@@ -0,0 +1,57 @@
+import { mdiCashMinus, mdiCashPlus, mdiCreditCard, mdiReceipt } from '@mdi/js'
+import React from 'react'
+import { ColorKey, Transaction } from '../interfaces'
+import BaseLevel from './BaseLevel'
+import CardBox from './CardBox'
+import IconRounded from './IconRounded'
+import PillTag from './PillTag'
+
+type Props = {
+ transaction: Transaction
+}
+
+const CardBoxTransaction = (props: Props) => {
+ const icon = {
+ withdraw: mdiCashMinus,
+ deposit: mdiCashPlus,
+ invoice: mdiReceipt,
+ payment: mdiCreditCard,
+ }[props.transaction.type]
+
+ const typeColor = () => {
+ switch (props.transaction.type) {
+ case 'withdraw':
+ return 'danger'
+ case 'deposit':
+ return 'success'
+ case 'invoice':
+ return 'warning'
+ case 'payment':
+ return 'info'
+ }
+ }
+
+ return (
+
+
+
+
+
+
{props.transaction.amount}
+
+ {props.transaction.date} via {props.transaction.business}
+
+
+
+
+
{props.transaction.name}
+
+
+
+
+ )
+}
+
+export default CardBoxTransaction
diff --git a/components/CardBoxWIdget.tsx b/components/CardBoxWIdget.tsx
index e69de29..120ee95 100644
--- a/components/CardBoxWIdget.tsx
+++ b/components/CardBoxWIdget.tsx
@@ -0,0 +1,61 @@
+import { mdiCog } from '@mdi/js'
+import React from 'react'
+import { ColorKey, TrendType } from '../interfaces'
+import { colorsText } from '../src/colors'
+import BaseButton from './BaseButton'
+import BaseIcon from './BaseIcon'
+import BaseLevel from './BaseLevel'
+import CardBox from './CardBox'
+import NumberDynamic from './NumberDynamic'
+import PillTagTrend from './PillTagTrend'
+
+type Props = {
+ number: number
+ numberPrefix?: string
+ numberSuffix?: string
+ icon: string
+ iconColor: ColorKey
+ label: string
+ trendLabel?: string
+ trendType?: TrendType
+ trendColor?: ColorKey
+}
+
+const CardBoxWidget = (props: Props) => {
+ return (
+
+ {props.trendLabel && props.trendType && props.trendColor && (
+
+
+
+
+ )}
+
+
+
{props.label}
+
+ {props.numberPrefix}
+ {props.number}
+ {props.numberSuffix}
+
+
+ {props.icon && (
+
+ )}
+
+
+ )
+}
+
+export default CardBoxWidget
diff --git a/components/IconRounded.tsx b/components/IconRounded.tsx
index 16d30ec..f2343e4 100644
--- a/components/IconRounded.tsx
+++ b/components/IconRounded.tsx
@@ -4,11 +4,11 @@ import { colorsBgLight, colorsText } from '../src/colors'
import BaseIcon from './BaseIcon'
type Props = {
- icon: string,
- color: ColorKey,
- w?: string,
- h?: string,
- bg?: boolean,
+ icon: string
+ color: ColorKey
+ w?: string
+ h?: string
+ bg?: boolean
className?: string
}
diff --git a/components/NavBar.tsx b/components/NavBar.tsx
index 31cb638..22b9952 100644
--- a/components/NavBar.tsx
+++ b/components/NavBar.tsx
@@ -7,13 +7,12 @@ import NavBarMenuList from './NavBarMenuList'
import { MenuNavBarItem } from '../interfaces'
type Props = {
- menu: MenuNavBarItem[],
- handleMenuClick: Function,
- className: string,
+ menu: MenuNavBarItem[]
+ className: string
children: ReactNode
}
-export default function NavBar({ menu, handleMenuClick, className='', children }: Props) {
+export default function NavBar({ menu, className = '', children }: Props) {
const [isMenuNavBarActive, setIsMenuNavBarActive] = useState(false)
const handleMenuNavBarToggleClick = (e: MouseEvent) => {
@@ -38,7 +37,7 @@ export default function NavBar({ menu, handleMenuClick, className='', children }
isMenuNavBarActive ? 'block' : 'hidden'
} max-h-screen-menu overflow-y-auto lg:overflow-visible absolute w-screen top-14 left-0 bg-gray-50 shadow-lg lg:w-auto lg:flex lg:static lg:shadow-none dark:bg-slate-800`}
>
-
+
diff --git a/components/NavBarItem.tsx b/components/NavBarItem.tsx
index 0779ae6..08c1734 100644
--- a/components/NavBarItem.tsx
+++ b/components/NavBarItem.tsx
@@ -6,15 +6,17 @@ import BaseDivider from './BaseDivider'
import BaseIcon from './BaseIcon'
import UserAvatarCurrentUser from './UserAvatarCurrentUser'
import NavBarMenuList from './NavBarMenuList'
-import { useAppSelector } from '../src/stores/hooks'
+import { useAppDispatch, useAppSelector } from '../src/stores/hooks'
import { MenuNavBarItem } from '../interfaces'
+import { setDarkMode } from '../src/stores/styleSlice'
type Props = {
- item: MenuNavBarItem,
- onClick: Function,
+ item: MenuNavBarItem
}
-export default function NavBarItem({ item, onClick }: Props) {
+export default function NavBarItem({ item }: Props) {
+ const dispatch = useAppDispatch()
+
const navBarItemLabelActiveColorStyle = useAppSelector(
(state) => state.style.navBarItemLabelActiveColorStyle
)
@@ -38,11 +40,11 @@ export default function NavBarItem({ item, onClick }: Props) {
const handleMenuClick = (e: React.MouseEvent) => {
if (item.menu) {
- setIsDropdownActive(!isDropdownActive);
+ setIsDropdownActive(!isDropdownActive)
}
- if (onClick) {
- onClick(e);
+ if (item.isToggleLightDark) {
+ dispatch(setDarkMode(null))
}
}
diff --git a/components/NavBarItemPlain.tsx b/components/NavBarItemPlain.tsx
index 6e85034..c1a888f 100644
--- a/components/NavBarItemPlain.tsx
+++ b/components/NavBarItemPlain.tsx
@@ -2,13 +2,18 @@ import React, { ReactNode } from 'react'
import { useAppSelector } from '../src/stores/hooks'
type Props = {
- display?: string,
- useMargin?: boolean,
- children: ReactNode,
+ display?: string
+ useMargin?: boolean
+ children: ReactNode
onClick?: Function
}
-export default function NavBarItemPlain({ display = 'flex', useMargin = false, onClick, children }: Props) {
+export default function NavBarItemPlain({
+ display = 'flex',
+ useMargin = false,
+ onClick,
+ children,
+}: Props) {
const navBarItemLabelStyle = useAppSelector((state) => state.style.navBarItemLabelStyle)
const navBarItemLabelHoverStyle = useAppSelector((state) => state.style.navBarItemLabelHoverStyle)
@@ -19,9 +24,13 @@ export default function NavBarItemPlain({ display = 'flex', useMargin = false, o
const handleClick = (e: React.MouseEvent) => {
if (onClick) {
- onClick(e);
+ onClick(e)
}
}
- return
{children}
diff --git a/components/PillTag.tsx b/components/PillTag.tsx
new file mode 100644
index 0000000..9648db1
--- /dev/null
+++ b/components/PillTag.tsx
@@ -0,0 +1,28 @@
+import React from 'react'
+import { ColorKey } from '../interfaces'
+import { colorsBgLight, colorsOutline } from '../src/colors'
+import PillTagPlain from './PillTagPlain'
+
+type Props = {
+ label?: string
+ color: ColorKey
+ icon?: string
+ small?: boolean
+ outline?: boolean
+}
+
+const PillTag = ({ small = false, outline = false, ...props }: Props) => {
+ const layoutClassName = small ? 'py-1 px-3' : 'py-1.5 px-4'
+ const colorClassName = outline ? colorsOutline[props.color] : colorsBgLight[props.color]
+
+ return (
+
+ )
+}
+
+export default PillTag
diff --git a/components/PillTagPlain.tsx b/components/PillTagPlain.tsx
new file mode 100644
index 0000000..87a348a
--- /dev/null
+++ b/components/PillTagPlain.tsx
@@ -0,0 +1,32 @@
+import React from 'react'
+import BaseIcon from './BaseIcon'
+
+type Props = {
+ label?: string
+ icon?: string
+ className?: string
+ small?: boolean
+}
+
+const PillTagPlain = ({ small = false, className = '', ...props }: Props) => {
+ return (
+
+ {props.icon && (
+
+ )}
+ {props.label && {props.label}}
+
+ )
+}
+
+export default PillTagPlain
diff --git a/components/PillTagTrend.tsx b/components/PillTagTrend.tsx
new file mode 100644
index 0000000..4a9a067
--- /dev/null
+++ b/components/PillTagTrend.tsx
@@ -0,0 +1,34 @@
+import React from 'react'
+import {
+ mdiChevronUp,
+ mdiChevronDown,
+ mdiAlertCircleOutline,
+ mdiInformationOutline,
+ mdiCheckAll,
+ mdiCheckCircleOutline,
+ mdiAlertOutline,
+} from '@mdi/js'
+import { ColorKey, TrendType } from '../interfaces'
+import PillTag from './PillTag'
+
+type Props = {
+ label: string
+ type: TrendType
+ color: ColorKey
+ small?: boolean
+}
+
+const PillTagTrend = ({ small = false, ...props }: Props) => {
+ const trendIcon = {
+ up: mdiChevronUp,
+ down: mdiChevronDown,
+ success: mdiCheckCircleOutline,
+ danger: mdiAlertOutline,
+ warning: mdiAlertCircleOutline,
+ info: mdiInformationOutline,
+ }[props.type]
+
+ return
+}
+
+export default PillTagTrend
diff --git a/components/SectionBanner.tsx b/components/SectionBanner.tsx
new file mode 100644
index 0000000..b66d6c3
--- /dev/null
+++ b/components/SectionBanner.tsx
@@ -0,0 +1,14 @@
+import React, { ReactNode } from 'react'
+
+type Props = {
+ className?: string
+ children: ReactNode
+}
+
+const SectionBanner = ({ className = '', children }: Props) => {
+ return (
+
{children}
+ )
+}
+
+export default SectionBanner
diff --git a/components/SectionBannerStarOnGitHub.tsx b/components/SectionBannerStarOnGitHub.tsx
new file mode 100644
index 0000000..452efa3
--- /dev/null
+++ b/components/SectionBannerStarOnGitHub.tsx
@@ -0,0 +1,26 @@
+import { mdiGithub } from '@mdi/js'
+import React from 'react'
+import { gradientBgPinkRed } from '../src/colors'
+import BaseButton from './BaseButton'
+import SectionBanner from './SectionBanner'
+
+const SectionBannerStarOnGitHub = () => {
+ return (
+
+
+ Like the project? Please star on GitHub ;-)
+
+
+
+
+
+ )
+}
+
+export default SectionBannerStarOnGitHub
diff --git a/components/SectionFullScreen.tsx b/components/SectionFullScreen.tsx
index f121c1d..246d0f7 100644
--- a/components/SectionFullScreen.tsx
+++ b/components/SectionFullScreen.tsx
@@ -4,7 +4,7 @@ import { gradientBgPurplePink, gradientBgDark, gradientBgPinkRed } from '../src/
import { useAppSelector } from '../src/stores/hooks'
type Props = {
- bg: BgKey,
+ bg: BgKey
children: ReactNode
}
diff --git a/components/SectionTitleLineWithButton.tsx b/components/SectionTitleLineWithButton.tsx
index 32a7824..8643c86 100644
--- a/components/SectionTitleLineWithButton.tsx
+++ b/components/SectionTitleLineWithButton.tsx
@@ -5,9 +5,9 @@ import BaseIcon from './BaseIcon'
import IconRounded from './IconRounded'
type Props = {
- icon: string,
- title: string,
- main?: boolean,
+ icon: string
+ title: string
+ main?: boolean
children?: ReactNode
}
diff --git a/components/TableSampleClients.tsx b/components/TableSampleClients.tsx
new file mode 100644
index 0000000..18fd2e5
--- /dev/null
+++ b/components/TableSampleClients.tsx
@@ -0,0 +1,96 @@
+import { mdiEye, mdiTrashCan } from '@mdi/js'
+import React, { useState } from 'react'
+import { useSampleClients } from '../hooks/sampleData'
+import { Client } from '../interfaces'
+import BaseButton from './BaseButton'
+import BaseButtons from './BaseButtons'
+import BaseLevel from './BaseLevel'
+import UserAvatar from './UserAvatar'
+
+const TableSampleClients = () => {
+ const { clients } = useSampleClients()
+
+ const perPage = 5
+
+ const [currentPage, setCurrentPage] = useState(0)
+
+ const clientsPaginated = clients.slice(perPage * currentPage, perPage * (currentPage + 1))
+
+ const numPages = clients.length / perPage
+
+ const pagesList = []
+
+ for (let i = 0; i < numPages; i++) {
+ pagesList.push(i)
+ }
+
+ return (
+ <>
+
+
+
+ |
+ Name |
+ Company |
+ City |
+ Progress |
+ Created |
+ |
+
+
+
+ {clientsPaginated.map((client: Client) => (
+
+
+
+ |
+ {client.name} |
+ {client.company} |
+ {client.city} |
+
+
+ |
+
+ {client.created}
+ |
+
+
+
+
+
+ |
+
+ ))}
+
+
+
+
+
+ {pagesList.map((page) => (
+ setCurrentPage(page)}
+ />
+ ))}
+
+
+ Page {currentPage + 1} of {numPages}
+
+
+
+ >
+ )
+}
+
+export default TableSampleClients
diff --git a/components/UserAvatar.tsx b/components/UserAvatar.tsx
index 3d2dd85..6f93123 100644
--- a/components/UserAvatar.tsx
+++ b/components/UserAvatar.tsx
@@ -1,26 +1,29 @@
import React, { ReactNode } from 'react'
-import Image from 'next/image'
type Props = {
- username: string,
- avatar?: string|null,
- api?: string,
- className?: string,
+ username: string
+ avatar?: string | null
+ api?: string
+ className?: string
children?: ReactNode
}
-export default function UserAvatar({ username, avatar=null, api = 'avataaars', className='', children }: Props) {
+export default function UserAvatar({
+ username,
+ avatar = null,
+ api = 'avataaars',
+ className = '',
+ children,
+}: Props) {
const avatarImage =
avatar ?? `https://avatars.dicebear.com/api/${api}/${username.replace(/[^a-z0-9]+/i, '-')}.svg`
return (
-
-
+
{children}
diff --git a/components/UserAvatarCurrentUser.tsx b/components/UserAvatarCurrentUser.tsx
index 624a183..2d68f21 100644
--- a/components/UserAvatarCurrentUser.tsx
+++ b/components/UserAvatarCurrentUser.tsx
@@ -3,11 +3,11 @@ import { useAppSelector } from '../src/stores/hooks'
import UserAvatar from './UserAvatar'
type Props = {
- className?: string,
+ className?: string
children?: ReactNode
}
-export default function UserAvatarCurrentUser({ className='', children }: Props) {
+export default function UserAvatarCurrentUser({ className = '', children }: Props) {
const userName = useAppSelector((state) => state.main.userName)
const userAvatar = useAppSelector((state) => state.main.userAvatar)
diff --git a/components/charts/LineSample.tsx b/components/charts/LineSample.tsx
new file mode 100644
index 0000000..c7f417b
--- /dev/null
+++ b/components/charts/LineSample.tsx
@@ -0,0 +1,37 @@
+import React from 'react'
+import {
+ Chart,
+ LineElement,
+ PointElement,
+ LineController,
+ LinearScale,
+ CategoryScale,
+ Tooltip,
+} from 'chart.js'
+import { Line } from 'react-chartjs-2'
+
+Chart.register(LineElement, PointElement, LineController, LinearScale, CategoryScale, Tooltip)
+
+const options = {
+ responsive: true,
+ maintainAspectRatio: false,
+ scales: {
+ y: {
+ display: false,
+ },
+ x: {
+ display: true,
+ },
+ },
+ plugins: {
+ legend: {
+ display: false,
+ },
+ },
+}
+
+const ChartLineSample = ({ data }) => {
+ return
+}
+
+export default ChartLineSample
diff --git a/components/charts/config.ts b/components/charts/config.ts
new file mode 100644
index 0000000..cacce92
--- /dev/null
+++ b/components/charts/config.ts
@@ -0,0 +1,54 @@
+export const chartColors = {
+ default: {
+ primary: '#00D1B2',
+ info: '#209CEE',
+ danger: '#FF3860',
+ },
+}
+
+const randomChartData = (n: number) => {
+ const data = []
+
+ for (let i = 0; i < n; i++) {
+ data.push(Math.round(Math.random() * 200))
+ }
+
+ return data
+}
+
+const datasetObject = (color: string, points: number) => {
+ return {
+ fill: false,
+ borderColor: chartColors.default[color],
+ borderWidth: 2,
+ borderDash: [],
+ borderDashOffset: 0.0,
+ pointBackgroundColor: chartColors.default[color],
+ pointBorderColor: 'rgba(255,255,255,0)',
+ pointHoverBackgroundColor: chartColors.default[color],
+ pointBorderWidth: 20,
+ pointHoverRadius: 4,
+ pointHoverBorderWidth: 15,
+ pointRadius: 4,
+ data: randomChartData(points),
+ tension: 0.5,
+ cubicInterpolationMode: 'default',
+ }
+}
+
+export const sampleChartData = (points = 9) => {
+ const labels = []
+
+ for (let i = 1; i <= points; i++) {
+ labels.push(`0${i}`)
+ }
+
+ return {
+ labels,
+ datasets: [
+ datasetObject('primary', points),
+ datasetObject('info', points),
+ datasetObject('danger', points),
+ ],
+ }
+}
diff --git a/components/globals/DarkMode.tsx b/components/globals/DarkMode.tsx
index cb52935..027d484 100644
--- a/components/globals/DarkMode.tsx
+++ b/components/globals/DarkMode.tsx
@@ -1,15 +1,22 @@
-import { darkModeKey } from '../../src/config'
+import { useEffect } from 'react'
+import { localStorageDarkModeKey } from '../../src/config'
import { useAppDispatch } from '../../src/stores/hooks'
import { setDarkMode } from '../../src/stores/styleSlice'
export default function GlobalDarkMode() {
const dispatch = useAppDispatch()
- const isSetInLocalStorage = typeof localStorage !== 'undefined' && localStorage[darkModeKey]
- const isSetInMedia =
- typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches
+ useEffect(() => {
+ const isSetInLocalStorage =
+ typeof localStorage !== 'undefined' && localStorage[localStorageDarkModeKey]
- dispatch(setDarkMode(isSetInLocalStorage ? localStorage[darkModeKey] === '1' : isSetInMedia))
+ const isSetInMedia =
+ typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches
+ dispatch(
+ setDarkMode(isSetInLocalStorage ? localStorage[localStorageDarkModeKey] === '1' : isSetInMedia)
+ )
+ })
+
return null
}
diff --git a/components/globals/Style.tsx b/components/globals/Style.tsx
index 4572995..91d7891 100644
--- a/components/globals/Style.tsx
+++ b/components/globals/Style.tsx
@@ -1,17 +1,20 @@
-import { styleKey } from '../../src/config'
+import { useEffect } from 'react'
+import { localStorageStyleKey } from '../../src/config'
import { useAppDispatch } from '../../src/stores/hooks'
import { setStyle } from '../../src/stores/styleSlice'
export default function GlobalStyle() {
const dispatch = useAppDispatch()
- dispatch(
- setStyle(
- typeof localStorage !== 'undefined' && localStorage[styleKey]
- ? localStorage[styleKey]
- : 'basic'
+ useEffect(() => {
+ dispatch(
+ setStyle(
+ typeof localStorage !== 'undefined' && localStorage[localStorageStyleKey]
+ ? localStorage[localStorageStyleKey]
+ : 'basic'
+ )
)
- )
+ })
return null
}
diff --git a/components/justboil/Logo.tsx b/components/justboil/Logo.tsx
index 3c6e8a7..927745c 100644
--- a/components/justboil/Logo.tsx
+++ b/components/justboil/Logo.tsx
@@ -5,7 +5,7 @@ type Props = {
className?: string
}
-export default function JustboilLogo({ className='' }: Props) {
+export default function JustboilLogo({ className = '' }: Props) {
return (