├── src
├── components
│ ├── Frame
│ │ ├── index.ts
│ │ ├── frame.css
│ │ ├── Frame.tsx
│ │ └── SidebarFooter.tsx
│ ├── Logo
│ │ ├── index.tsx
│ │ ├── logo.css
│ │ └── Logo.tsx
│ ├── ErrorPage
│ │ ├── index.ts
│ │ ├── error-page.css
│ │ └── ErrorPage.tsx
│ ├── index.ts
│ ├── PageContent.tsx
│ ├── Copyright.tsx
│ ├── NavLink.tsx
│ ├── Brand.tsx
│ └── PageToolbar.tsx
├── app
│ ├── (main)
│ │ ├── error
│ │ │ ├── 403
│ │ │ │ ├── page.tsx
│ │ │ │ └── Error403.tsx
│ │ │ ├── 404
│ │ │ │ ├── page.tsx
│ │ │ │ └── Error404.tsx
│ │ │ ├── 500
│ │ │ │ ├── page.tsx
│ │ │ │ └── Error500.tsx
│ │ │ └── 503
│ │ │ │ ├── page.tsx
│ │ │ │ └── Error503.tsx
│ │ ├── layout.tsx
│ │ ├── table
│ │ │ ├── members
│ │ │ │ ├── members-table.css
│ │ │ │ ├── page.tsx
│ │ │ │ ├── DrawerView.tsx
│ │ │ │ ├── Cells.tsx
│ │ │ │ ├── DataTable.tsx
│ │ │ │ └── users.ts
│ │ │ └── virtualized
│ │ │ │ ├── page.tsx
│ │ │ │ └── VirtualizedTable.tsx
│ │ ├── dashboard
│ │ │ ├── colorful-chart.css
│ │ │ ├── page.tsx
│ │ │ ├── dashboard.css
│ │ │ ├── PieChart.tsx
│ │ │ ├── ColorfulChart.tsx
│ │ │ ├── dashboard-chartist.css
│ │ │ ├── BarChart.tsx
│ │ │ ├── DataTable.tsx
│ │ │ └── Dashboard.tsx
│ │ ├── form
│ │ │ ├── wizard
│ │ │ │ ├── FormHeader.tsx
│ │ │ │ ├── page.tsx
│ │ │ │ ├── Completed.tsx
│ │ │ │ ├── ProjectTypeForm.tsx
│ │ │ │ ├── WizardForm.tsx
│ │ │ │ ├── BusinessDetailForm.tsx
│ │ │ │ ├── ProjectInfoForm.tsx
│ │ │ │ └── TeamSettingsForm.tsx
│ │ │ └── basic
│ │ │ │ ├── page.tsx
│ │ │ │ ├── form-basic.css
│ │ │ │ └── BasicForm.tsx
│ │ ├── page.tsx
│ │ └── calendar
│ │ │ ├── page.tsx
│ │ │ ├── EventModal.tsx
│ │ │ ├── Calendar.tsx
│ │ │ └── calendar.css
│ ├── not-found.tsx
│ ├── sign-in
│ │ ├── page.tsx
│ │ └── SignIn.tsx
│ ├── sign-up
│ │ ├── page.tsx
│ │ └── SignUp.tsx
│ ├── providers.tsx
│ ├── page.tsx
│ ├── layout.tsx
│ ├── auth.css
│ └── globals.css
├── utils
│ ├── toThousands.ts
│ ├── index.ts
│ ├── formatValue.ts
│ └── highlightValue.tsx
├── hooks
│ └── useWindowHeight.ts
├── config.tsx
└── data
│ ├── mock.ts
│ └── calendarEvents.ts
├── public
├── favicon.ico
└── images
│ ├── preview-1.png
│ ├── preview-2.png
│ ├── errors
│ ├── index.ts
│ ├── 403.svg
│ └── 500.svg
│ ├── pv.svg
│ ├── uv.svg
│ └── vv.svg
├── .prettierrc.js
├── .eslintignore
├── next.config.js
├── .eslintrc.json
├── tsconfig.json
├── .gitignore
├── README.md
└── package.json
/src/components/Frame/index.ts:
--------------------------------------------------------------------------------
1 | import Frame from './Frame';
2 |
3 | export default Frame;
4 |
--------------------------------------------------------------------------------
/src/components/Logo/index.tsx:
--------------------------------------------------------------------------------
1 | import Logo from './Logo';
2 |
3 | export default Logo;
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsuite/rsuite-admin-template/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/components/ErrorPage/index.ts:
--------------------------------------------------------------------------------
1 | import ErrorPage from './ErrorPage';
2 |
3 | export default ErrorPage;
4 |
--------------------------------------------------------------------------------
/public/images/preview-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsuite/rsuite-admin-template/HEAD/public/images/preview-1.png
--------------------------------------------------------------------------------
/public/images/preview-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsuite/rsuite-admin-template/HEAD/public/images/preview-2.png
--------------------------------------------------------------------------------
/src/components/index.ts:
--------------------------------------------------------------------------------
1 | export { default as ErrorPage } from './ErrorPage';
2 | export { default as Frame } from './Frame';
3 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | printWidth: 100,
3 | tabWidth: 2,
4 | singleQuote: true,
5 | arrowParens: 'avoid',
6 | trailingComma: 'none'
7 | };
8 |
--------------------------------------------------------------------------------
/src/app/(main)/error/403/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import Error403 from './Error403';
4 |
5 | export default function Error403Page() {
6 | return ;
7 | }
8 |
--------------------------------------------------------------------------------
/src/app/(main)/error/404/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import Error404 from './Error404';
4 |
5 | export default function Error404Page() {
6 | return ;
7 | }
8 |
--------------------------------------------------------------------------------
/src/app/(main)/error/500/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import Error500 from './Error500';
4 |
5 | export default function Error500Page() {
6 | return ;
7 | }
8 |
--------------------------------------------------------------------------------
/src/app/(main)/error/503/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import Error503 from './Error503';
4 |
5 | export default function Error503Page() {
6 | return ;
7 | }
8 |
--------------------------------------------------------------------------------
/src/app/not-found.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import Error404 from './(main)/error/404/Error404';
4 |
5 | export default function NotFound() {
6 | return ;
7 | }
8 |
--------------------------------------------------------------------------------
/src/app/sign-in/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import '../auth.css';
4 | import SignIn from './SignIn';
5 |
6 | export default function SignInPage() {
7 | return ;
8 | }
9 |
--------------------------------------------------------------------------------
/src/app/sign-up/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import '../auth.css';
4 | import SignUp from './SignUp';
5 |
6 | export default function SignUpPage() {
7 | return ;
8 | }
9 |
--------------------------------------------------------------------------------
/src/utils/toThousands.ts:
--------------------------------------------------------------------------------
1 | export default function toThousands(value: number, fixed = 0) {
2 | return (value.toFixed(fixed) + '').replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,');
3 | }
4 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | node_modules
3 | pnpm-lock.yaml
4 |
5 | # Build outputs
6 | .next
7 | out
8 | dist
9 |
10 | # Environment files
11 | .env
12 | .env.local
13 | .env.*.local
14 |
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | export { default as toThousands } from './toThousands';
2 | export { default as highlightValue } from './highlightValue';
3 | export { default as formatValue } from './formatValue';
4 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | images: {
4 | unoptimized: true
5 | },
6 | transpilePackages: ['@fullcalendar'],
7 | turbopack: {}
8 | };
9 |
10 | module.exports = nextConfig;
11 |
--------------------------------------------------------------------------------
/src/app/(main)/layout.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import Frame from '@/components/Frame';
4 | import { appNavs } from '@/config';
5 |
6 | export default function MainLayout({ children }: { children: React.ReactNode }) {
7 | return {children};
8 | }
9 |
--------------------------------------------------------------------------------
/src/app/providers.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import React from 'react';
4 | import { CustomProvider } from 'rsuite';
5 | import enGB from 'rsuite/locales/en_GB';
6 |
7 | export function Providers({ children }: { children: React.ReactNode }) {
8 | return {children} ;
9 | }
10 |
--------------------------------------------------------------------------------
/public/images/errors/index.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-var-requires */
2 | export const { default: Error404Img } = require('./404.svg');
3 | export const { default: Error500Img } = require('./500.svg');
4 | export const { default: Error503Img } = require('./503.svg');
5 | export const { default: Error403Img } = require('./403.svg');
6 |
--------------------------------------------------------------------------------
/src/app/(main)/table/members/members-table.css:
--------------------------------------------------------------------------------
1 | .rs-table .link-group {
2 | cursor: pointer;
3 | }
4 |
5 | .rs-table .link-group .rs-table-cell-content {
6 | padding: 5px;
7 | }
8 |
9 | /* Tables - Members */
10 | .table-toolbar {
11 | padding: 20px;
12 | background: var(--table-bg);
13 | border-radius: 4px 4px 0 0;
14 | }
15 |
--------------------------------------------------------------------------------
/src/app/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useEffect } from 'react';
4 | import { useRouter } from 'next/navigation';
5 | import { Loader } from 'rsuite';
6 |
7 | export default function HomePage() {
8 | const router = useRouter();
9 |
10 | useEffect(() => {
11 | router.push('/dashboard');
12 | }, [router]);
13 |
14 | return ;
15 | }
16 |
--------------------------------------------------------------------------------
/src/app/(main)/dashboard/colorful-chart.css:
--------------------------------------------------------------------------------
1 | .colorful-chart {
2 | color: var(--colorful-chart-text);
3 | margin-top: 30px;
4 | border-radius: 6px;
5 | }
6 |
7 | .colorful-chart h3 {
8 | line-height: 22px;
9 | text-align: right;
10 | color: var(--colorful-chart-title);
11 | padding: 10px;
12 | font-size: 18px;
13 | }
14 |
15 |
16 |
17 | .apexcharts-theme-light .tooltip-custom {
18 | color: var(--tooltip-text);
19 | }
20 |
--------------------------------------------------------------------------------
/src/app/(main)/form/wizard/FormHeader.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | interface FormHeaderProps {
4 | title: string;
5 | description: string;
6 | }
7 |
8 | const FormHeader = ({ title, description }: FormHeaderProps) => {
9 | return (
10 |
11 |
{title}
12 |
{description}
13 |
14 | );
15 | };
16 |
17 | export default FormHeader;
18 |
--------------------------------------------------------------------------------
/src/app/(main)/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { Panel } from 'rsuite';
4 | import Dashboard from './dashboard/Dashboard';
5 | import Copyright from '@/components/Copyright';
6 | import PageToolbar from '@/components/PageToolbar';
7 |
8 | export default function HomePage() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/src/components/PageContent.tsx:
--------------------------------------------------------------------------------
1 | import { Panel, PanelProps } from 'rsuite';
2 | import classNames from 'classnames';
3 | import Copyright from '@/components/Copyright';
4 |
5 | const PageContent = (props: PanelProps) => {
6 | const { className, ...rest } = props;
7 | return (
8 | <>
9 |
10 |
11 | >
12 | );
13 | };
14 |
15 | export default PageContent;
16 |
--------------------------------------------------------------------------------
/src/app/(main)/dashboard/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import dynamic from 'next/dynamic';
4 | import { Panel } from 'rsuite';
5 | import Dashboard from './Dashboard';
6 | import Copyright from '@/components/Copyright';
7 |
8 | const PageToolbar = dynamic(() => import('@/components/PageToolbar'), { ssr: false });
9 |
10 | export default function DashboardPage() {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/ErrorPage/error-page.css:
--------------------------------------------------------------------------------
1 | .error-page {
2 | display: flex;
3 | height: 100vh;
4 | margin-top: -40px;
5 | justify-content: center;
6 | align-items: center;
7 | }
8 |
9 | .error-page-code {
10 | color: var(--text-muted);
11 | }
12 |
13 | .error-page-title {
14 | font-size: 1.5rem;
15 | font-weight: bold;
16 | }
17 |
18 | .error-page-subtitle {
19 | margin: 10px 0 20px 0;
20 | }
21 |
22 | .error-page .item img {
23 | height: 260px;
24 | }
25 |
26 | .error-page .item .text {
27 | text-align: center;
28 | }
29 |
--------------------------------------------------------------------------------
/src/components/Copyright.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Stack } from 'rsuite';
3 |
4 | const Copyright = () => {
5 | return (
6 |
7 |
15 |
16 | );
17 | };
18 |
19 | export default Copyright;
20 |
--------------------------------------------------------------------------------
/src/app/(main)/error/503/Error503.tsx:
--------------------------------------------------------------------------------
1 | import ErrorPage from '@/components/ErrorPage';
2 | import { IconButton } from 'rsuite';
3 | import { FiArrowLeft } from 'react-icons/fi';
4 |
5 | const Error503 = () => (
6 |
7 | Oops… You just found an error page
8 | This page is being updated and maintained.
9 | } appearance="primary" href="/">
10 | Take me home
11 |
12 |
13 | );
14 |
15 | export default Error503;
16 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "parser": "@typescript-eslint/parser",
4 | "parserOptions": {
5 | "ecmaVersion": 2020,
6 | "sourceType": "module"
7 | },
8 | "plugins": ["@typescript-eslint", "react-hooks"],
9 | "extends": [
10 | "plugin:@typescript-eslint/recommended",
11 | "plugin:react-hooks/recommended",
12 | "prettier"
13 | ],
14 | "ignorePatterns": ["node_modules", ".next", "pnpm-lock.yaml"],
15 | "rules": {
16 | "@typescript-eslint/no-explicit-any": "warn",
17 | "react-hooks/exhaustive-deps": "warn",
18 | "react/react-in-jsx-scope": "off"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/app/(main)/error/404/Error404.tsx:
--------------------------------------------------------------------------------
1 | import ErrorPage from '@/components/ErrorPage';
2 | import { IconButton } from 'rsuite';
3 | import { FiArrowLeft } from 'react-icons/fi';
4 |
5 | const Error404 = () => (
6 |
7 | Oops… You just found an error page
8 |
9 | We are sorry but the page you are looking for was not found
10 |
11 | } appearance="primary" href="/">
12 | Take me home
13 |
14 |
15 | );
16 |
17 | export default Error404;
18 |
--------------------------------------------------------------------------------
/src/app/(main)/error/500/Error500.tsx:
--------------------------------------------------------------------------------
1 | import ErrorPage from '@/components/ErrorPage';
2 | import { IconButton } from 'rsuite';
3 | import { FiArrowLeft } from 'react-icons/fi';
4 |
5 | const Error500 = () => (
6 |
7 | Oops… You just found an error page
8 |
9 | We are sorry but our server encountered an internal error
10 |
11 | } appearance="primary" href="/">
12 | Take me home
13 |
14 |
15 | );
16 |
17 | export default Error500;
18 |
--------------------------------------------------------------------------------
/src/app/(main)/error/403/Error403.tsx:
--------------------------------------------------------------------------------
1 | import ErrorPage from '@/components/ErrorPage';
2 | import { IconButton } from 'rsuite';
3 | import { FiArrowLeft } from 'react-icons/fi';
4 |
5 | const Error403 = () => (
6 |
7 | Oops… You just found an error page
8 |
9 | The current page is unavailable or you do not have permission to access.{' '}
10 |
11 | } appearance="primary" href="/">
12 | Take me home
13 |
14 |
15 | );
16 |
17 | export default Error403;
18 |
--------------------------------------------------------------------------------
/src/app/(main)/calendar/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { Panel, Breadcrumb, Text, VStack } from 'rsuite';
4 | import Calendar from './Calendar';
5 |
6 | export default function CalendarPage() {
7 | return (
8 |
11 |
12 | Calendar
13 |
14 |
15 | Home
16 | Calendar
17 |
18 |
19 | }
20 | >
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/Logo/logo.css:
--------------------------------------------------------------------------------
1 | .rsuite-logo .cls-1 {
2 | fill: #6292f0;
3 | }
4 |
5 | .rsuite-logo .cls-2 {
6 | fill: #ec727d;
7 | }
8 |
9 | .rsuite-logo .cls-1,
10 | .rsuite-logo .cls-2 {
11 | fill-rule: evenodd;
12 | }
13 |
14 | .rsuite-logo .polyline-limb {
15 | animation: limbLineMove 3s ease-out 1;
16 | }
17 |
18 | .rsuite-logo .polyline-axis {
19 | animation: axisLineMove 2s ease-out 1;
20 | }
21 |
22 | .rsuite-logo .circle {
23 | animation: circleMove 2s ease-out 1;
24 | }
25 |
26 | .logo-animated {
27 | animation-duration: 1s;
28 | animation-fill-mode: both;
29 | }
30 |
31 | .logo-animated-delay-half-seconds {
32 | animation-delay: 0.5s;
33 | }
--------------------------------------------------------------------------------
/src/components/ErrorPage/ErrorPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Image from 'next/image';
3 | import './error-page.css';
4 |
5 | interface ErrorPageProps {
6 | code?: number;
7 | children?: React.ReactNode;
8 | }
9 |
10 | const ErrorPage = ({ code = 404, children }: ErrorPageProps) => (
11 |
12 |
13 |
14 |
15 |
{code}
16 | {children}
17 |
18 |
19 |
20 | );
21 |
22 | export default ErrorPage;
23 |
--------------------------------------------------------------------------------
/src/components/NavLink.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import React from 'react';
4 | import Link from 'next/link';
5 |
6 | interface NavLinkProps {
7 | to?: string;
8 | children?: React.ReactNode;
9 | [key: string]: any;
10 | }
11 |
12 | const NavLink = React.forwardRef(
13 | ({ to, children, ...rest }, ref) => {
14 | if (!to) {
15 | return (
16 |
17 | {children}
18 |
19 | );
20 | }
21 | return (
22 |
23 | {children}
24 |
25 | );
26 | }
27 | );
28 |
29 | NavLink.displayName = 'NavLink';
30 |
31 | export default NavLink;
32 |
--------------------------------------------------------------------------------
/src/app/(main)/form/basic/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { Breadcrumb, Panel, Text, VStack } from 'rsuite';
4 | import BasicForm from './BasicForm';
5 |
6 | export default function FormBasicPage() {
7 | return (
8 |
11 |
12 | Basic Form
13 |
14 |
15 | Home
16 | Forms
17 | Basic
18 |
19 |
20 | }
21 | >
22 |
23 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/src/app/(main)/table/members/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { Breadcrumb, Panel, Text, VStack } from 'rsuite';
4 | import DataTable from './DataTable';
5 |
6 | export default function MembersPage() {
7 | return (
8 |
11 |
12 | Members
13 |
14 |
15 | Home
16 | Tables
17 | Members
18 |
19 |
20 | }
21 | >
22 |
23 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/src/app/(main)/form/wizard/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { Breadcrumb, Panel, Text, VStack } from 'rsuite';
4 | import WizardForm from './WizardForm';
5 |
6 | export default function FormWizardPage() {
7 | return (
8 |
11 |
12 | Wizard Form
13 |
14 |
15 | Home
16 | Forms
17 | Wizard
18 |
19 |
20 | }
21 | >
22 |
23 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/src/utils/formatValue.ts:
--------------------------------------------------------------------------------
1 | import toThousands from './toThousands';
2 |
3 | export default function formatValue(value: number) {
4 | if (value === null || typeof value === 'undefined') {
5 | return '--';
6 | } else if (value === 0) {
7 | return '0';
8 | } else if (0 < value && value < 1000) {
9 | return '< 1k';
10 | } else if (1000 <= value && value < 1000000) {
11 | return toThousands(value / 1000) + ' k';
12 | } else if (1000000 <= value && value < 1000000000) {
13 | return toThousands(value / 1000000) + ' M';
14 | } else if (1000000000 <= value && value < 1000000000000) {
15 | return toThousands(value / 1000000000) + ' B';
16 | } else if (1000000000000 <= value) {
17 | return 'INF.';
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Providers } from './providers';
3 | import 'rsuite/dist/rsuite.css';
4 | import './globals.css';
5 |
6 | export const metadata = {
7 | title: 'React Suite Admin Template',
8 | description: 'A modern React Suite admin dashboard template built with Next.js and RSuite.',
9 | keywords: [
10 | 'React Suite',
11 | 'RSuite',
12 | 'admin template',
13 | 'dashboard',
14 | 'Next.js',
15 | 'management system'
16 | ]
17 | };
18 |
19 | export default function RootLayout({ children }: { children: React.ReactNode }) {
20 | return (
21 |
22 |
23 | {children}
24 |
25 |
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/src/app/(main)/table/virtualized/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { Breadcrumb, Panel, Text, VStack } from 'rsuite';
4 | import VirtualizedTable from './VirtualizedTable';
5 |
6 | export default function VirtualizedTablePage() {
7 | return (
8 |
11 |
12 | Virtualized Table
13 |
14 |
15 | Home
16 | Tables
17 | Virtualized
18 |
19 |
20 | }
21 | >
22 |
23 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/Brand.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import React from 'react';
4 | import Link from 'next/link';
5 | import Logo from './Logo';
6 | import { Stack, Text, HStack } from 'rsuite';
7 |
8 | interface BrandProps {
9 | collapsed?: boolean;
10 | }
11 |
12 | const Brand = ({ collapsed, ...rest }: BrandProps & React.HTMLAttributes) => {
13 | if (collapsed) {
14 | return (
15 |
16 |
17 |
18 | );
19 | }
20 |
21 | return (
22 |
23 |
24 |
25 | Admin Template
26 |
27 |
28 | );
29 | };
30 |
31 | export default Brand;
32 |
--------------------------------------------------------------------------------
/src/hooks/useWindowHeight.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 |
3 | function getHeight(win: Window | undefined): number {
4 | if (typeof window === 'undefined' || !win) return 0;
5 | return win.innerHeight || win.document.documentElement.clientHeight || win.document.body.clientHeight;
6 | }
7 |
8 | export function useWindowHeight(): number {
9 | const [windowHeight, setWindowHeight] = useState(0);
10 |
11 | useEffect(() => {
12 | if (typeof window !== 'undefined') {
13 | setWindowHeight(getHeight(window));
14 |
15 | const handleResize = () => setWindowHeight(getHeight(window));
16 | window.addEventListener('resize', handleResize);
17 |
18 | return () => {
19 | window.removeEventListener('resize', handleResize);
20 | };
21 | }
22 | }, []);
23 |
24 | return windowHeight;
25 | }
26 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": [
4 | "dom",
5 | "dom.iterable",
6 | "esnext"
7 | ],
8 | "allowJs": true,
9 | "skipLibCheck": true,
10 | "strict": true,
11 | "noEmit": true,
12 | "esModuleInterop": true,
13 | "module": "esnext",
14 | "moduleResolution": "bundler",
15 | "resolveJsonModule": true,
16 | "isolatedModules": true,
17 | "jsx": "react-jsx",
18 | "incremental": true,
19 | "plugins": [
20 | {
21 | "name": "next"
22 | }
23 | ],
24 | "paths": {
25 | "@/*": [
26 | "./src/*"
27 | ]
28 | },
29 | "target": "ES2017"
30 | },
31 | "include": [
32 | "next-env.d.ts",
33 | "**/*.ts",
34 | "**/*.tsx",
35 | ".next/types/**/*.ts",
36 | ".next/dev/types/**/*.ts"
37 | ],
38 | "exclude": [
39 | "node_modules"
40 | ]
41 | }
42 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | karma-*
6 |
7 | # Runtime data
8 | pids
9 | *.pid
10 | *.seed
11 |
12 | # Directory for instrumented libs generated by jscoverage/JSCover
13 | lib-cov
14 |
15 | # Coverage directory used by tools like istanbul
16 | coverage
17 |
18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
19 | .grunt
20 |
21 | # node-waf configuration
22 | .lock-wscript
23 |
24 | # Compiled binary addons (http://nodejs.org/api/addons.html)
25 | build/Release
26 |
27 | # Dependency directory
28 | node_modules
29 |
30 | # Optional npm cache directory
31 | .npm
32 |
33 | # Optional REPL history
34 | .node_repl_history
35 |
36 | # custom
37 |
38 | .vscode
39 | .DS_Store
40 | .idea
41 | scripts
42 | build
43 | lib
44 | dist
45 | assets
46 |
47 | # Next.js
48 | .next/
49 | out/
50 | next-env.d.ts
51 |
52 | # TypeScript
53 | *.tsbuildinfo
54 |
--------------------------------------------------------------------------------
/src/utils/highlightValue.tsx:
--------------------------------------------------------------------------------
1 | import toThousands from './toThousands';
2 |
3 | const Highlight = ({ value, unit }: { value: string; unit: string }) => (
4 |
5 | {value} {unit}{' '}
6 |
7 | );
8 |
9 | export default function highlightValue(value: number, fixed: number) {
10 | if (value === null || typeof value === 'undefined') {
11 | return '--';
12 | } else if (value === 0) {
13 | return '0';
14 | } else if (0 < value && value < 1000) {
15 | return '< 1k';
16 | } else if (1000 <= value && value < 1000000) {
17 | return ;
18 | } else if (1000000 <= value && value < 1000000000) {
19 | return ;
20 | } else if (1000000000 <= value) {
21 | return ;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/Frame/frame.css:
--------------------------------------------------------------------------------
1 | .frame {
2 | display: flex;
3 | height: 100vh;
4 | }
5 |
6 | .frame .rs-sidebar {
7 | background: var(--bg-sidebar);
8 | flex-shrink: 0;
9 | }
10 |
11 | .frame > .rs-container {
12 | flex: 1;
13 | display: flex;
14 | flex-direction: column;
15 | min-width: 0;
16 | }
17 |
18 | .frame .rs-sidenav {
19 | transition: none !important;
20 | border-top: 1px solid var(--border-color);
21 | width: 100%;
22 | }
23 |
24 | .frame .rs-content {
25 | flex: 1;
26 | overflow-y: auto;
27 | padding: 0 10px;
28 | }
29 |
30 | .frame .rs-content .rs-panel-header .title {
31 | font-size: 18px;
32 | }
33 |
34 | .frame .rs-content .rs-panel-header .rs-breadcrumb {
35 | margin-bottom: 0;
36 | }
37 |
38 | .frame .rs-sidenav-item.active,
39 | .frame .rs-dropdown-item.active {
40 | color: var(--active-color) !important;
41 | }
42 |
43 | .frame .rs-sidenav-item-icon,
44 | .frame .rs-dropdown-item-icon {
45 | height: 1.3em !important;
46 | width: 1.3em !important;
47 | }
48 |
--------------------------------------------------------------------------------
/src/app/(main)/dashboard/dashboard.css:
--------------------------------------------------------------------------------
1 | .dashboard-header .rs-panel {
2 | color: #fff;
3 | }
4 |
5 | .dashboard-header .chart-img {
6 | width: 100px;
7 | position: absolute;
8 | left: 26px;
9 | top: 34px;
10 | opacity: 0.5;
11 | }
12 |
13 | .dashboard-header .trend-box .rs-panel-body {
14 | text-align: right;
15 | }
16 |
17 | .dashboard-header .trend-box .rs-panel-body .value {
18 | font-size: 36px;
19 | }
20 |
21 | .bg-gradient-orange {
22 | background: linear-gradient(
23 | 87deg,
24 | var(--bg-gradient-orange-from) 0,
25 | var(--bg-gradient-orange-to) 100%
26 | );
27 | }
28 |
29 | .bg-gradient-red {
30 | background: linear-gradient(87deg, var(--bg-gradient-red-from) 0, var(--bg-gradient-red-to) 100%);
31 | }
32 |
33 | .bg-gradient-green {
34 | background: linear-gradient(
35 | 87deg,
36 | var(--bg-gradient-green-from) 0,
37 | var(--bg-gradient-green-to) 100%
38 | );
39 | }
40 |
41 | .bg-gradient-blue {
42 | background: linear-gradient(
43 | 87deg,
44 | var(--bg-gradient-blue-from) 0,
45 | var(--bg-gradient-blue-to) 100%
46 | );
47 | }
48 |
--------------------------------------------------------------------------------
/src/app/(main)/form/wizard/Completed.tsx:
--------------------------------------------------------------------------------
1 | import { ButtonToolbar, Button, Stack } from 'rsuite';
2 | import { FiCheckCircle } from 'react-icons/fi';
3 |
4 | const Completed = () => {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 |
Your Are Done!
12 |
You can start working on a new project.
13 |
14 |
15 |
16 |
17 |
18 | Once you have created this project, if you return to Project Web App you see it listed as a
19 | project in the Project Center. Updates made to the task list on the project site are
20 | reflected in the Project Center in Project Web App.
21 |
22 |
You can also click the button below to start working on the project.
23 |
24 |
25 | View Project
26 | Add permissions to the project
27 |
28 |
29 | );
30 | };
31 |
32 | export default Completed;
33 |
--------------------------------------------------------------------------------
/src/app/(main)/dashboard/PieChart.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import Chart, { Props as ChartProps } from 'react-apexcharts';
4 | import { Panel } from 'rsuite';
5 |
6 | interface PieChartProps {
7 | title: string;
8 | data: ChartProps['series'];
9 | type?: ChartProps['type'];
10 | options?: ChartProps['options'];
11 | labels?: string[];
12 | }
13 |
14 | const defaultOptions = {
15 | dataLabels: {
16 | enabled: false
17 | },
18 | plotOptions: {
19 | pie: {
20 | customScale: 0.8,
21 | donut: {
22 | size: '75%'
23 | },
24 | offsetY: 0
25 | },
26 | stroke: {
27 | colors: undefined
28 | }
29 | },
30 | colors: [
31 | 'var(--chart-pie-series-1)',
32 | 'var(--chart-pie-series-2)',
33 | 'var(--chart-pie-series-3)',
34 | 'var(--chart-pie-series-4)',
35 | 'var(--chart-pie-series-5)'
36 | ],
37 | legend: {
38 | position: 'bottom',
39 | offsetY: 0
40 | }
41 | };
42 |
43 | const PieChart = ({ title, data, type, labels, options }: PieChartProps) => (
44 |
45 |
51 |
52 | );
53 |
54 | export default PieChart;
55 |
--------------------------------------------------------------------------------
/src/app/(main)/dashboard/ColorfulChart.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import classNames from 'classnames';
4 | import Chart, { Props as ChartProps } from 'react-apexcharts';
5 | import './colorful-chart.css';
6 |
7 | interface ColorfulChartProps {
8 | className?: string;
9 | title: string;
10 | data: ChartProps['series'];
11 | type?: ChartProps['type'];
12 | options?: ChartProps['options'];
13 | }
14 |
15 | const defaultOptions = {
16 | chart: {
17 | id: 'sparkline1',
18 | type: 'line',
19 | height: 140,
20 | sparkline: {
21 | enabled: true
22 | },
23 | group: 'sparklines'
24 | },
25 | stroke: {
26 | curve: 'smooth'
27 | },
28 | markers: {
29 | size: 0
30 | },
31 | tooltip: {
32 | cssClass: 'tooltip-custom',
33 | marker: {
34 | show: false
35 | },
36 | fixed: {
37 | enabled: true,
38 | position: 'right'
39 | },
40 | x: {
41 | show: false
42 | }
43 | },
44 | colors: ['var(--chart-sparkline-color)']
45 | };
46 |
47 | const ColorfulChart = ({ className, title, data, type, options }: ColorfulChartProps) => (
48 |
49 |
{title}
50 |
56 |
57 | );
58 |
59 | export default ColorfulChart;
60 |
--------------------------------------------------------------------------------
/src/app/(main)/dashboard/dashboard-chartist.css:
--------------------------------------------------------------------------------
1 | .ct-chart-magenta {
2 | background: linear-gradient(
3 | 60deg,
4 | var(--chart-magenta-from, #ec407a),
5 | var(--chart-magenta-to, #d81b60)
6 | );
7 | }
8 |
9 | .ct-chart-orange {
10 | background: linear-gradient(
11 | 60deg,
12 | var(--chart-orange-from, #ffa726),
13 | var(--chart-orange-to, #fb8c00)
14 | );
15 | }
16 |
17 | .ct-chart-azure {
18 | background: linear-gradient(
19 | 60deg,
20 | var(--chart-azure-from, #26c6da),
21 | var(--chart-azure-to, #00acc1)
22 | );
23 | }
24 |
25 | .ct-chart-magenta .ct-label,
26 | .ct-chart-orange .ct-label,
27 | .ct-chart-azure .ct-label {
28 | color: var(--chart-label-color);
29 | }
30 |
31 | .ct-chart-magenta .ct-series-a .ct-bar,
32 | .ct-chart-magenta .ct-series-a .ct-slice-donut,
33 | .ct-chart-magenta .ct-series-a .ct-line,
34 | .ct-chart-magenta .ct-series-a .ct-point,
35 | .ct-chart-orange .ct-series-a .ct-bar,
36 | .ct-chart-orange .ct-series-a .ct-slice-donut,
37 | .ct-chart-orange .ct-series-a .ct-line,
38 | .ct-chart-orange .ct-series-a .ct-point,
39 | .ct-chart-azure .ct-series-a .ct-bar,
40 | .ct-chart-azure .ct-series-a .ct-slice-donut,
41 | .ct-chart-azure .ct-series-a .ct-line,
42 | .ct-chart-azure .ct-series-a .ct-point {
43 | stroke: var(--chart-stroke-color);
44 | }
45 |
46 | .ct-chart-magenta .ct-grid,
47 | .ct-chart-orange .ct-grid,
48 | .ct-chart-azure .ct-grid {
49 | stroke: var(--chart-grid-color);
50 | }
51 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RSuite Admin Template
2 |
3 | A Next.js + TypeScript admin dashboard template built with [RSuite](https://rsuitejs.com/).
4 |
5 | Provides a modern layout, prebuilt pages (dashboard, forms, calendar, auth, error pages) and a themeable design system based on CSS variables and RSuite themes.
6 |
7 | 
8 |
9 | 
10 |
11 | ## Tech stack
12 |
13 | - **Framework**: Next.js (App Router)
14 | - **UI Library**: RSuite
15 | - **Language**: TypeScript
16 | - **Styling**: CSS modules + global CSS variables (light / dark / system themes)
17 |
18 | ## Getting started
19 |
20 | Clone the repository:
21 |
22 | ```bash
23 | git clone git@github.com:/rsuite-admin-template.git
24 | cd rsuite-admin-template
25 | ```
26 |
27 | Install dependencies:
28 |
29 | ```bash
30 | npm install
31 | ```
32 |
33 | Run the development server (default: http://127.0.0.1:3000):
34 |
35 | ```bash
36 | npm run dev
37 | ```
38 |
39 | ## Scripts
40 |
41 | - `npm run dev` – Start the development server
42 | - `npm run build` – Create a production build
43 | - `npm run start` – Run the production build
44 |
45 | ## Theming
46 |
47 | The template uses CSS variables and RSuite theme tokens to support light, dark and system themes.
48 |
49 | - Global variables are defined in `src/app/globals.css`
50 | - Layout and components consume variables instead of hardcoded colors
51 | - Theme switching is implemented in the sidebar user menu
52 |
53 | ## License
54 |
55 | MIT
56 |
--------------------------------------------------------------------------------
/src/app/(main)/table/virtualized/VirtualizedTable.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useState, useEffect } from 'react';
4 | import { DOMHelper, Table } from 'rsuite';
5 | import { mockUsers } from '@/data/mock';
6 |
7 | const { Column, HeaderCell, Cell } = Table;
8 | const { getHeight } = DOMHelper;
9 |
10 | const data = mockUsers(1000);
11 |
12 | const VirtualizedTable = () => {
13 | const [tableHeight, setTableHeight] = useState(600);
14 |
15 | useEffect(() => {
16 | if (typeof window !== 'undefined') {
17 | setTableHeight(Math.max(getHeight(window) - 120, 400));
18 | }
19 | }, []);
20 |
21 | return (
22 |
28 |
29 | Id
30 | |
31 |
32 |
33 |
34 | First Name
35 | |
36 |
37 |
38 |
39 | Last Name
40 | |
41 |
42 |
43 |
44 | Gender
45 | |
46 |
47 |
48 |
49 | Age
50 | |
51 |
52 |
53 |
54 | City
55 | |
56 |
57 |
58 |
59 | Email
60 | |
61 |
62 |
63 | );
64 | };
65 |
66 | export default VirtualizedTable;
67 |
--------------------------------------------------------------------------------
/src/app/(main)/form/wizard/ProjectTypeForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { Form, Stack, RadioTile, RadioTileGroup } from 'rsuite';
3 | import { VscNotebookTemplate, VscRepoClone, VscFile } from 'react-icons/vsc';
4 | import FormHeader from './FormHeader';
5 |
6 | const ProjectTypeForm = () => {
7 | const [type, setType] = useState('personal');
8 |
9 | return (
10 |
44 | );
45 | };
46 |
47 | export default ProjectTypeForm;
48 |
--------------------------------------------------------------------------------
/src/app/(main)/form/wizard/WizardForm.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useState } from 'react';
4 | import { Steps, Divider, Stack, Button } from 'rsuite';
5 | import PageContent from '@/components/PageContent';
6 | import { FiChevronRight, FiChevronLeft } from 'react-icons/fi';
7 |
8 | import ProjectTypeForm from './ProjectTypeForm';
9 | import TeamSettingsForm from './TeamSettingsForm';
10 | import BusinessDetailForm from './BusinessDetailForm';
11 | import ProjectInfoForm from './ProjectInfoForm';
12 | import Completed from './Completed';
13 |
14 | const forms = [ProjectTypeForm, ProjectInfoForm, TeamSettingsForm, BusinessDetailForm, Completed];
15 |
16 | const WizardForm = () => {
17 | const [step, setStep] = useState(0);
18 | const Form = forms[step];
19 | return (
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | {step !== 0 && (
37 | } onClick={() => setStep(Math.max(step - 1, 0))}>
38 | Back
39 |
40 | )}
41 |
42 | {step !== forms.length - 1 && (
43 | }
45 | appearance="primary"
46 | onClick={() => setStep(Math.min(step + 1, 4))}
47 | >
48 | Continue
49 |
50 | )}
51 |
52 |
53 |
54 | );
55 | };
56 |
57 | export default WizardForm;
58 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rsuite-admin-template",
3 | "version": "1.0.0",
4 | "description": "React Suite Management System",
5 | "main": "lib/index.js",
6 | "directories": {
7 | "lib": "lib/"
8 | },
9 | "scripts": {
10 | "dev": "next dev",
11 | "build": "next build",
12 | "start": "next start",
13 | "lint": "eslint src --ext .js,.jsx,.ts,.tsx"
14 | },
15 | "keywords": [
16 | "react",
17 | "rsuite",
18 | "admin",
19 | "template"
20 | ],
21 | "files": [
22 | "CHANGELOG.md",
23 | "lib",
24 | "src"
25 | ],
26 | "author": "HYPERS Team",
27 | "license": "MIT",
28 | "repository": {
29 | "type": "git",
30 | "url": "git@github.com:rsuite/rsuite-admin-template.git"
31 | },
32 | "dependencies": {
33 | "@faker-js/faker": "^7.4.0",
34 | "@fullcalendar/core": "^6.1.15",
35 | "@fullcalendar/daygrid": "^6.1.15",
36 | "@fullcalendar/interaction": "^6.1.15",
37 | "@fullcalendar/react": "^6.1.15",
38 | "@fullcalendar/timegrid": "^6.1.15",
39 | "@rsuite/icons": "^1.4.0",
40 | "apexcharts": "^3.35.4",
41 | "classnames": "^2.3.1",
42 | "date-fns": "^4.0.0",
43 | "lodash": "^4.17.21",
44 | "next": "^16.0.0",
45 | "react": "^18.3.1",
46 | "react-apexcharts": "^1.9.0",
47 | "react-dom": "^18.3.1",
48 | "react-icons": "^5.5.0",
49 | "rsuite": "^6.0.1"
50 | },
51 | "devDependencies": {
52 | "@types/lodash": "^4.14.195",
53 | "@types/node": "^20.10.0",
54 | "@types/react": "^18.3.0",
55 | "@types/react-dom": "^18.3.0",
56 | "@typescript-eslint/eslint-plugin": "^6.13.0",
57 | "@typescript-eslint/parser": "^6.13.0",
58 | "eslint": "^8.57.0",
59 | "eslint-config-prettier": "^9.0.0",
60 | "eslint-plugin-react": "^7.33.2",
61 | "eslint-plugin-react-hooks": "^4.6.0",
62 | "prettier": "^3.1.0",
63 | "typescript": "^5.3.0"
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/app/(main)/dashboard/BarChart.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import React from 'react';
4 | import dynamic from 'next/dynamic';
5 | import type { Props as ChartProps } from 'react-apexcharts';
6 | const Chart = dynamic(() => import('react-apexcharts'), { ssr: false });
7 | import { Panel, Stack } from 'rsuite';
8 |
9 | interface BarChartProps {
10 | title?: React.ReactNode;
11 | actions?: React.ReactNode;
12 | data: ChartProps['series'];
13 | type?: ChartProps['type'];
14 | options?: ChartProps['options'];
15 | labels?: string[];
16 | }
17 |
18 | const defaultOptions = {
19 | chart: {
20 | fontFamily: 'inherit',
21 | parentHeightOffset: 0,
22 | toolbar: {
23 | show: false
24 | },
25 | animations: {
26 | enabled: false
27 | },
28 | stacked: true
29 | },
30 | plotOptions: {
31 | bar: {
32 | columnWidth: '50%'
33 | }
34 | },
35 | dataLabels: {
36 | enabled: false
37 | },
38 | fill: {
39 | opacity: 1
40 | },
41 | grid: {
42 | padding: {
43 | top: -20,
44 | right: 0,
45 | left: -4,
46 | bottom: -4
47 | },
48 | strokeDashArray: 4,
49 | xaxis: {
50 | lines: {
51 | show: true
52 | }
53 | }
54 | },
55 | xaxis: {
56 | tooltip: {
57 | enabled: false
58 | },
59 | axisBorder: {
60 | show: false
61 | },
62 | type: 'datetime'
63 | },
64 | yaxis: {
65 | labels: {
66 | padding: 4
67 | }
68 | },
69 | colors: ['var(--chart-bar-series-1)', 'var(--chart-bar-series-2)', 'var(--chart-bar-series-3)'],
70 | legend: {
71 | show: false
72 | }
73 | };
74 |
75 | const BarChart = ({ title, actions, data, type, labels, options }: BarChartProps) => (
76 |
80 | {title}
81 | {actions}
82 |
83 | }
84 | >
85 |
91 |
92 | );
93 |
94 | export default BarChart;
95 |
--------------------------------------------------------------------------------
/src/app/(main)/calendar/EventModal.tsx:
--------------------------------------------------------------------------------
1 | import type { MouseEvent } from 'react';
2 | import { Modal, Button, Form, DatePicker, ModalProps, Stack, Checkbox } from 'rsuite';
3 |
4 | interface EventModalProps extends ModalProps {
5 | onAddEvent: (event: MouseEvent) => void;
6 | }
7 |
8 | const EventModal = (props: EventModalProps) => {
9 | const { onClose, open, onAddEvent, ...rest } = props;
10 | return (
11 |
12 |
13 | Add a New Event
14 |
15 |
16 |
18 | Event Name
19 |
20 |
21 |
22 | Event Description
23 |
24 |
25 |
26 | Event Location
27 |
28 |
29 |
30 | Event Date
31 |
32 |
38 |
44 | All Day
45 |
46 |
47 |
48 |
49 |
50 |
51 | Submit
52 |
53 |
54 | Cancel
55 |
56 |
57 |
58 | );
59 | };
60 |
61 | export default EventModal;
62 |
--------------------------------------------------------------------------------
/src/app/(main)/dashboard/DataTable.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { Table, Panel } from 'rsuite';
4 |
5 | const { Column, HeaderCell, Cell } = Table;
6 |
7 | const data = [
8 | {
9 | id: 1,
10 | url: 'https://rsuitejs.com',
11 | visits: '105,253',
12 | unique: '23,361',
13 | bounce: '11%'
14 | },
15 | {
16 | id: 2,
17 | url: 'https://rsuitejs.com/components/overview/',
18 | visits: '103,643',
19 | unique: '23,385',
20 | bounce: '17%'
21 | },
22 | {
23 | id: 3,
24 | url: 'https://rsuitejs.com/components/table/',
25 | visits: '140,013',
26 | unique: '41,256',
27 | bounce: '13%'
28 | },
29 | {
30 | id: 4,
31 | url: 'https://rsuitejs.com/components/drawer/',
32 | visits: '194,532',
33 | unique: '19,038',
34 | bounce: '18%'
35 | },
36 | {
37 | id: 5,
38 | url: 'https://rsuitejs.com/guide/usage/',
39 | visits: '26,353',
40 | unique: '1,000',
41 | bounce: '20%'
42 | },
43 | {
44 | id: 6,
45 | url: 'https://rsuitejs.com/guide/customization/',
46 | visits: '11,973',
47 | unique: '4,786',
48 | bounce: '24%'
49 | }
50 | ];
51 |
52 | const DataTable = () => {
53 | return (
54 |
55 |
56 |
57 | PAGE NAME
58 |
59 | {rowData => {
60 | return (
61 |
62 | {rowData.url}
63 |
64 | );
65 | }}
66 | |
67 |
68 |
69 |
70 | VISITORS
71 | |
72 |
73 |
74 |
75 | UNIQUE
76 | |
77 |
78 |
79 |
80 | BOUNCE RATE
81 | |
82 |
83 |
84 |
85 | );
86 | };
87 |
88 | export default DataTable;
89 |
--------------------------------------------------------------------------------
/src/app/(main)/form/wizard/BusinessDetailForm.tsx:
--------------------------------------------------------------------------------
1 | import { Form, SelectPicker, Textarea } from 'rsuite';
2 | import FormHeader from './FormHeader';
3 |
4 | const BusinessDetailForm = () => {
5 | return (
6 |
13 | Business Name
14 |
15 |
16 |
17 |
18 | Shortened Descriptor
19 |
20 |
21 | Customers will see this shortened version of your statement descriptor.
22 |
23 |
24 |
25 |
26 | Corporation Type
27 |
45 |
46 | Different team sizes will be assigned different management modes. Of course the fees are
47 | different.
48 |
49 |
50 |
51 |
52 | Business Description
53 |
54 |
55 |
56 |
57 | Contact Email
58 |
59 |
60 |
61 | );
62 | };
63 |
64 | export default BusinessDetailForm;
65 |
--------------------------------------------------------------------------------
/src/app/(main)/calendar/Calendar.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useState } from 'react';
4 | import FullCalendar from '@fullcalendar/react';
5 | import type { DateSelectArg, EventClickArg, EventContentArg } from '@fullcalendar/core';
6 | import dayGridPlugin from '@fullcalendar/daygrid';
7 | import timeGridPlugin from '@fullcalendar/timegrid';
8 | import interactionPlugin from '@fullcalendar/interaction';
9 | import PageContent from '@/components/PageContent';
10 | import { INITIAL_EVENTS } from '@/data/calendarEvents';
11 | import EventModal from './EventModal';
12 | import './calendar.css';
13 |
14 | const Calendar = () => {
15 | const [editable, setEditable] = useState(false);
16 | const handleDateSelect = (selectInfo: DateSelectArg) => {
17 | console.log(selectInfo);
18 | setEditable(true);
19 | };
20 |
21 | const handleEventClick = (clickInfo: EventClickArg) => {
22 | console.log(clickInfo);
23 | setEditable(true);
24 | };
25 |
26 | return (
27 |
28 |
47 | setEditable(false)}
50 | onAddEvent={() => {
51 | setEditable(false);
52 | }}
53 | />
54 |
55 | );
56 | };
57 |
58 | function renderEventContent(eventContent: EventContentArg) {
59 | const { timeText, event } = eventContent;
60 | return (
61 | <>
62 | {timeText && (
63 | <>
64 |
65 | {eventContent.timeText}
66 | >
67 | )}
68 | {event.title}
69 | >
70 | );
71 | }
72 |
73 | export default Calendar;
74 |
--------------------------------------------------------------------------------
/src/app/(main)/calendar/calendar.css:
--------------------------------------------------------------------------------
1 | .rs-container .fc .fc-button {
2 | display: inline-block;
3 | margin-bottom: 0;
4 | font-weight: 400;
5 | text-align: center;
6 | vertical-align: middle;
7 | cursor: pointer;
8 | white-space: nowrap;
9 | transition: all 0.3s ease-in-out;
10 | border: var(--rs-btn-default-border, none);
11 | user-select: none;
12 | text-decoration: none;
13 | color: var(--rs-btn-default-text);
14 | background-color: var(--rs-btn-default-bg);
15 | border-radius: 6px;
16 | box-shadow: none !important;
17 | text-transform: capitalize;
18 | padding: 8px 12px;
19 | font-size: 14px;
20 | line-height: 1.42857;
21 | }
22 |
23 | .rs-container .fc .fc-button:hover {
24 | color: var(--rs-btn-default-hover-text);
25 | background-color: var(--rs-btn-default-hover-bg);
26 | text-decoration: none;
27 | }
28 |
29 | .rs-container .fc .fc-button:active {
30 | color: var(--rs-btn-default-active-text);
31 | background-color: var(--rs-btn-default-active-bg);
32 | }
33 |
34 | .rs-container .fc .fc-button:disabled {
35 | cursor: not-allowed;
36 | color: var(--rs-btn-default-disabled-text);
37 | background-color: var(--rs-btn-default-disabled-bg);
38 | }
39 |
40 | .rs-container .fc .fc-button.fc-button-active {
41 | color: var(--rs-btn-default-active-text) !important;
42 | background-color: var(--rs-btn-default-active-bg) !important;
43 | }
44 |
45 | .rs-container .fc .fc-col-header-cell-cushion {
46 | font-weight: 500;
47 | color: var(--rs-text-primary);
48 | }
49 |
50 | .rs-container .fc .fc-daygrid-day-number {
51 | color: var(--rs-text-primary);
52 | }
53 |
54 | .rs-container .fc .fc-scrollgrid {
55 | border: none;
56 | }
57 |
58 | .rs-container .fc .fc-scrollgrid td,
59 | .rs-container .fc .fc-scrollgrid th {
60 | border: 1px solid var(--rs-border-secondary);
61 | }
62 |
63 | .rs-container .fc .fc-scrollgrid th {
64 | height: 36px;
65 | line-height: 36px;
66 | }
67 |
68 | .rs-container .fc .fc-daygrid-event {
69 | margin-top: 1px;
70 | }
71 |
72 | .rs-container .fc .fc-daygrid-dot-event {
73 | padding: 4px;
74 | background-color: var(--rs-btn-default-bg);
75 | color: var(--rs-text-primary);
76 | }
77 |
78 | .rs-container .fc .fc-event-main {
79 | padding: 4px;
80 | }
81 |
82 | .rs-container .fc .fc-h-event {
83 | background-color: var(--rs-btn-primary-bg);
84 | color: var(--rs-btn-primary-text);
85 | border-color: var(--rs-btn-primary-bg);
86 | }
87 |
88 | .rs-container .fc .fc-event-title {
89 | font-weight: 200;
90 | }
91 |
--------------------------------------------------------------------------------
/src/app/(main)/form/wizard/ProjectInfoForm.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Form, Stack, InputGroup, Textarea, RadioTile, RadioTileGroup } from 'rsuite';
3 | import { VscLock, VscWorkspaceTrusted } from 'react-icons/vsc';
4 | import FormHeader from './FormHeader';
5 |
6 | const ProjectInfoForm = () => {
7 | const [level, setLevel] = React.useState('Private');
8 |
9 | return (
10 |
18 | Project Name
19 |
20 | Project names must be unique.
21 |
22 |
23 |
24 | Project URL
25 |
26 |
27 | https://rsuitejs.com/
28 |
29 |
30 |
31 | Want to house several dependent projects under the same namespace? Create a group.
32 |
33 |
34 |
35 |
36 | Project description (optional)
37 |
38 |
39 |
40 |
41 | Visibility Level
42 |
43 | setLevel(String(value))}>
44 | }
46 | label="Private"
47 | value="Private"
48 | >
49 | Project access must be granted explicitly to each user. If this project is part of a
50 | group, access will be granted to members of the group.
51 |
52 | }
54 | label="Internal"
55 | value="Internal"
56 | >
57 | The project can be accessed by any logged in user except external users.
58 |
59 |
60 |
61 |
62 |
63 | );
64 | };
65 |
66 | export default ProjectInfoForm;
67 |
--------------------------------------------------------------------------------
/src/config.tsx:
--------------------------------------------------------------------------------
1 | import { Icon } from '@rsuite/icons';
2 | import { VscTable, VscCalendar } from 'react-icons/vsc';
3 | import { MdFingerprint, MdDashboard, MdModeEditOutline } from 'react-icons/md';
4 | import { FaCubes } from 'react-icons/fa6';
5 |
6 | export const appNavs = [
7 | {
8 | eventKey: 'dashboard',
9 | icon: ,
10 | title: 'Dashboard',
11 | to: '/dashboard'
12 | },
13 | {
14 | eventKey: 'calendar',
15 | icon: ,
16 | title: 'Calendar',
17 | to: '/calendar'
18 | },
19 | {
20 | eventKey: 'tables',
21 | icon: ,
22 | title: 'Tables',
23 | to: '/table/members',
24 | children: [
25 | {
26 | eventKey: 'members',
27 | title: 'Members',
28 | to: '/table/members'
29 | },
30 | {
31 | eventKey: 'virtualized',
32 | title: 'Virtualized Table',
33 | to: '/table/virtualized'
34 | }
35 | ]
36 | },
37 | {
38 | eventKey: 'forms',
39 | icon: ,
40 | title: 'Forms',
41 | to: '/form/basic',
42 | children: [
43 | {
44 | eventKey: 'form-basic',
45 | title: 'Basic',
46 | to: '/form/basic'
47 | },
48 | {
49 | eventKey: 'form-wizard',
50 | title: 'Wizard',
51 | to: '/form/wizard'
52 | }
53 | ]
54 | },
55 | {
56 | eventKey: 'authentication',
57 | title: 'Authentication',
58 | icon: ,
59 | children: [
60 | {
61 | eventKey: 'sign-in',
62 | title: 'Sign In',
63 | to: '/sign-in'
64 | },
65 |
66 | {
67 | eventKey: 'sign-up',
68 | title: 'Sign Up',
69 | to: '/sign-up'
70 | },
71 | {
72 | eventKey: 'error403',
73 | title: 'Error 403',
74 | to: '/error/403'
75 | },
76 | {
77 | eventKey: 'error404',
78 | title: 'Error 404',
79 | to: '/error/404'
80 | },
81 | {
82 | eventKey: 'error500',
83 | title: 'Error 500',
84 | to: '/error/500'
85 | },
86 | {
87 | eventKey: 'error503',
88 | title: 'Error 503',
89 | to: '/error/503'
90 | }
91 | ]
92 | },
93 |
94 | {
95 | eventKey: 'components',
96 | title: 'Components',
97 | icon: ,
98 | href: 'https://rsuitejs.com/components/overview/',
99 | target: '_blank'
100 | }
101 | ];
102 |
--------------------------------------------------------------------------------
/src/app/(main)/table/members/DrawerView.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Drawer,
3 | DrawerProps,
4 | Button,
5 | Form,
6 | Stack,
7 | NumberInput,
8 | InputGroup,
9 | Slider,
10 | Rate
11 | } from 'rsuite';
12 |
13 | const DrawerView = (props: DrawerProps) => {
14 | const { onClose, ...rest } = props;
15 | return (
16 |
17 |
18 | Add a new member
19 |
20 |
21 | Confirm
22 |
23 |
24 | Cancel
25 |
26 |
27 |
28 |
29 |
30 |
42 | Email
43 |
44 |
45 |
46 | City
47 |
48 |
49 |
50 | Street
51 |
52 |
53 |
54 |
55 | Rating
56 |
57 |
58 |
59 |
60 | Skill Proficiency
61 |
62 |
63 |
64 |
65 | Income
66 |
67 | $
68 |
69 |
70 |
71 |
72 |
73 |
74 | );
75 | };
76 |
77 | export default DrawerView;
78 |
--------------------------------------------------------------------------------
/src/app/sign-up/SignUp.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import React from 'react';
4 | import { Form, Button, Stack, Checkbox, PasswordInput } from 'rsuite';
5 |
6 | import Link from 'next/link';
7 |
8 | const SignUp = () => {
9 | return (
10 |
11 |
12 |
13 |
RSUITE
14 |
Join Our Platform
15 |
16 | Create your account and start building amazing applications with our powerful admin
17 | template.
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
Create Account
26 |
27 | Already have an account? Sign in here
28 |
29 |
30 |
31 |
33 | Username
34 |
35 |
36 |
37 |
38 | Email
39 |
40 |
41 |
42 |
43 | Password
44 |
49 |
50 |
51 |
52 | Confirm Password
53 |
58 |
59 |
60 |
61 |
62 | I agree to the
63 | Terms and Conditions
64 |
65 |
66 |
67 |
68 |
69 | Create Account
70 |
71 |
72 |
73 |
74 |
75 |
76 | );
77 | };
78 |
79 | export default SignUp;
80 |
--------------------------------------------------------------------------------
/src/data/mock.ts:
--------------------------------------------------------------------------------
1 | import { faker } from '@faker-js/faker/locale/en';
2 |
3 | export function mockUsers(length: number) {
4 | const createRowData = (rowIndex: number) => {
5 | const firstName = faker.name.firstName();
6 | const lastName = faker.name.lastName();
7 | const gender = faker.name.gender(true) as 'female' | 'male';
8 |
9 | const name = faker.name.fullName({ firstName, lastName, sex: gender });
10 | const avatar = `https://i.pravatar.cc/150?u=${faker.datatype.number({ min: 1, max: 10000 })}`;
11 |
12 | const city = faker.address.city();
13 | const street = faker.address.street();
14 | const email = faker.internet.email();
15 | const postcode = faker.address.zipCode();
16 | const phone = faker.phone.number();
17 | const amount = faker.finance.amount(1000, 90000);
18 |
19 | const age = Math.floor(Math.random() * 30) + 18;
20 | const stars = Math.floor(Math.random() * 10000);
21 | const followers = Math.floor(Math.random() * 10000);
22 | const rating = 2 + Math.floor(Math.random() * 3);
23 | const progress = Math.floor(Math.random() * 100);
24 |
25 | return {
26 | id: rowIndex + 1,
27 | name,
28 | firstName,
29 | lastName,
30 | avatar,
31 | city,
32 | street,
33 | postcode,
34 | email,
35 | phone,
36 | gender,
37 | age,
38 | stars,
39 | followers,
40 | rating,
41 | progress,
42 | amount
43 | };
44 | };
45 |
46 | return Array.from({ length }).map((_, index) => {
47 | return createRowData(index);
48 | });
49 | }
50 |
51 | export function mockTreeData(options: {
52 | limits: number[];
53 | labels: string | string[] | ((layer: number, value: string, faker: any) => string);
54 | getRowData?: (layer: number, value: string) => any[];
55 | }) {
56 | const { limits, labels, getRowData } = options;
57 | const depth = limits.length;
58 |
59 | const data: any[] = [];
60 | const mock = (list: any[], parentValue?: string, layer = 0) => {
61 | const length = limits[layer];
62 |
63 | Array.from({ length }).forEach((_, index) => {
64 | const value = parentValue ? parentValue + '-' + (index + 1) : index + 1 + '';
65 | const children: any[] = [];
66 | const label = Array.isArray(labels) ? labels[layer] : labels;
67 |
68 | let row: any = {
69 | label: typeof label === 'function' ? label(layer, value, faker) : label + ' ' + value,
70 | value
71 | };
72 |
73 | if (getRowData) {
74 | row = {
75 | ...row,
76 | ...getRowData(layer, value)
77 | };
78 | }
79 |
80 | list.push(row);
81 |
82 | if (layer < depth - 1) {
83 | row.children = children;
84 | mock(children, value, layer + 1);
85 | }
86 | });
87 | };
88 |
89 | mock(data);
90 |
91 | return data;
92 | }
93 |
--------------------------------------------------------------------------------
/src/data/calendarEvents.ts:
--------------------------------------------------------------------------------
1 | import type { EventInput } from '@fullcalendar/core';
2 | import uniqueId from 'lodash/uniqueId';
3 | import { startOfMonth, addDays, format, endOfMonth } from 'date-fns';
4 |
5 | const today = new Date();
6 | const firstDay = startOfMonth(today);
7 | const lastDay = endOfMonth(today);
8 | const todayStr = format(today, 'yyyy-MM-dd');
9 |
10 | export const INITIAL_EVENTS: EventInput[] = [
11 | {
12 | id: uniqueId(),
13 | title: '🎊 Project kick-off meeting',
14 | allDay: true,
15 | start: format(firstDay, 'yyyy-MM-dd')
16 | },
17 | {
18 | id: uniqueId(),
19 | title: '🎉 Product launch',
20 | start: format(addDays(firstDay, 2), 'yyyy-MM-dd') + 'T10:00:00'
21 | },
22 |
23 | {
24 | id: uniqueId(),
25 | title: 'Product training.',
26 | start: format(addDays(firstDay, 3), 'yyyy-MM-dd') + 'T10:00:00'
27 | },
28 | {
29 | id: uniqueId(),
30 | title: 'Product Demo',
31 | start: format(addDays(firstDay, 3), 'yyyy-MM-dd') + 'T11:00:00'
32 | },
33 | {
34 | id: uniqueId(),
35 | title: 'Product Exam',
36 | start: format(addDays(firstDay, 3), 'yyyy-MM-dd') + 'T12:00:00'
37 | },
38 |
39 | {
40 | id: uniqueId(),
41 | title: 'Monitoring and alerting service design communication',
42 | start: format(addDays(firstDay, 5), 'yyyy-MM-dd') + 'T10:00:00'
43 | },
44 | {
45 | id: uniqueId(),
46 | title: 'Design system brainstorming',
47 | start: format(addDays(firstDay, 5), 'yyyy-MM-dd') + 'T11:00:00'
48 | },
49 |
50 | {
51 | id: uniqueId(),
52 | title: 'Test Case Review',
53 | start: format(addDays(firstDay, 15), 'yyyy-MM-dd') + 'T14:00:00'
54 | },
55 | {
56 | id: uniqueId(),
57 | title: 'Development Design Review',
58 | start: format(addDays(firstDay, 15), 'yyyy-MM-dd') + 'T16:00:00'
59 | },
60 |
61 | {
62 | id: uniqueId(),
63 | title: '💎 Product meeting',
64 | start: todayStr + 'T09:00:00',
65 | end: todayStr + 'T10:30:00'
66 | },
67 | {
68 | id: uniqueId(),
69 | title: '👨💻 Coding ',
70 | start: todayStr + 'T10:00:00',
71 | end: todayStr + 'T11:30:00'
72 | },
73 | {
74 | id: uniqueId(),
75 | title: '📖 Leadership training',
76 | start: todayStr + 'T12:00:00',
77 | end: todayStr + 'T14:00:00'
78 | },
79 | {
80 | id: uniqueId(),
81 | title: '☕️ Afternoon tea time',
82 | start: todayStr + 'T14:00:00',
83 | end: todayStr + 'T16:00:00'
84 | },
85 | {
86 | id: uniqueId(),
87 | title: 'Interview engineers.',
88 | start: todayStr + 'T16:00:00',
89 | end: todayStr + 'T18:00:00'
90 | },
91 | {
92 | id: uniqueId(),
93 | title: '🎉 Product release',
94 | allDay: true,
95 | start: format(lastDay, 'yyyy-MM-dd') + 'T14:00:00'
96 | },
97 | {
98 | id: uniqueId(),
99 | title: '🔬 Product acceptance',
100 | start: format(lastDay, 'yyyy-MM-dd') + 'T16:00:00'
101 | }
102 | ];
103 |
--------------------------------------------------------------------------------
/src/app/(main)/form/basic/form-basic.css:
--------------------------------------------------------------------------------
1 | /* Form Basic Page - Flat Clean Layout */
2 |
3 | /* Header Section */
4 | .form-basic-header {
5 | margin-bottom: 40px;
6 | }
7 |
8 | .form-basic-title {
9 | font-size: 1.75rem;
10 | font-weight: 600;
11 | color: var(--text-primary);
12 | margin-bottom: 8px;
13 | }
14 |
15 | .form-basic-description {
16 | font-size: 0.9375rem;
17 | color: var(--text-tertiary);
18 | line-height: 1.6;
19 | }
20 |
21 | .form-basic-description a {
22 | color: var(--link-color);
23 | text-decoration: none;
24 | }
25 |
26 | .form-basic-description a:hover {
27 | text-decoration: underline;
28 | }
29 |
30 | /* Form Sections */
31 | .form-section {
32 | margin-bottom: 48px;
33 | width: 100%;
34 | }
35 |
36 | .form-section-title {
37 | font-size: 1.125rem;
38 | font-weight: 600;
39 | color: var(--text-secondary);
40 | margin-bottom: 16px;
41 | }
42 |
43 | .form-section .rs-divider {
44 | margin: 0 0 24px 0;
45 | }
46 |
47 | /* Full-width form groups (span both columns) */
48 | .form-group-full {
49 | grid-column: 1 / -1;
50 | }
51 | .form-group-full.align-center {
52 | align-items: center;
53 | }
54 | .form-group-full.align-start {
55 | align-items: flex-start;
56 | }
57 |
58 | /* Form Group Styling */
59 | .basic-form .rs-form-group {
60 | margin-bottom: 0;
61 | }
62 |
63 | .basic-form .rs-form-control-label-wrapper,
64 | .basic-form .rs-form-control-label {
65 | font-weight: 500;
66 | color: var(--form-label-color);
67 | margin-bottom: 8px;
68 | font-size: 0.875rem;
69 | }
70 |
71 | /* Checkbox and Radio Groups */
72 | .basic-form .rs-checkbox-group,
73 | .basic-form .rs-radio-group {
74 | padding: 4px 0;
75 | }
76 |
77 | .basic-form .rs-checkbox,
78 | .basic-form .rs-radio {
79 | margin-right: 20px;
80 | font-size: 0.875rem;
81 | }
82 |
83 | /* Form Actions */
84 | .form-actions {
85 | width: 100%;
86 | margin-top: 40px;
87 | padding-top: 24px;
88 | border-top: 1px solid var(--divider-color);
89 | display: flex;
90 | }
91 |
92 | .form-actions .rs-btn-toolbar {
93 | gap: 12px;
94 | }
95 |
96 | .form-actions .rs-btn {
97 | min-width: 100px;
98 | }
99 |
100 | /* Responsive Design */
101 | @media (max-width: 968px) {
102 | .form-grid {
103 | grid-template-columns: 1fr;
104 | gap: 20px;
105 | }
106 |
107 | .form-group-full {
108 | grid-column: 1;
109 | }
110 |
111 | .form-basic-title {
112 | font-size: 1.5rem;
113 | }
114 |
115 | .form-section {
116 | margin-bottom: 40px;
117 | }
118 |
119 | .form-actions .rs-btn-toolbar {
120 | flex-direction: column;
121 | width: 100%;
122 | }
123 |
124 | .form-actions .rs-btn {
125 | width: 100%;
126 | }
127 | }
128 |
129 | @media (max-width: 576px) {
130 | .form-basic-header {
131 | margin-bottom: 32px;
132 | }
133 |
134 | .form-section {
135 | margin-bottom: 32px;
136 | }
137 |
138 | .form-grid {
139 | gap: 16px;
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/src/app/(main)/form/wizard/TeamSettingsForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { Form, Stack, SelectPicker, RadioTile, RadioTileGroup } from 'rsuite';
3 | import { FaGit, FaGithub, FaGitlab } from 'react-icons/fa';
4 |
5 | import FormHeader from './FormHeader';
6 |
7 | const TeamSettingsForm = () => {
8 | const [type, setType] = useState('1');
9 |
10 | return (
11 |
18 | Team Name
19 |
20 |
21 |
22 |
23 | Specify Team Size
24 | 5 people' },
30 | { value: 2, label: '5-20 people' },
31 | { value: 3, label: '20-50 people' },
32 | { value: 4, label: '50+ people' }
33 | ]}
34 | block
35 | />
36 |
37 | Different team sizes will be assigned different management modes. Of course the fees are
38 | different.
39 |
40 |
41 |
42 |
43 | Choose a team workflow
44 |
45 | setType(String(value))}>
46 | }
48 | label="Git Flow"
49 | value="1"
50 | >
51 | Considered to be a bit complicated and advanced for many of today’s projects, GitFlow
52 | enables parallel development where developers can work separately from the master branch
53 | on features where a feature branch is created from the master branch.
54 |
55 | }
57 | label="GitHub Flow"
58 | value="2"
59 | >
60 | GitHub Flow is a simpler alternative to GitFlow ideal for smaller teams as they don’t
61 | need to manage multiple versions.
62 |
63 |
64 | }
66 | label="GitLab Flow"
67 | value="3"
68 | >
69 | GitLab Flow is a simpler alternative to GitFlow that combines feature-driven development
70 | and feature branching with issue tracking.
71 |
72 |
73 |
74 |
75 |
76 | );
77 | };
78 |
79 | export default TeamSettingsForm;
80 |
--------------------------------------------------------------------------------
/src/components/Frame/Frame.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/ban-ts-comment */
2 | 'use client';
3 |
4 | import React, { useState } from 'react';
5 | import { Container, Sidebar, Sidenav, Content, Nav, useMediaQuery } from 'rsuite';
6 | import NavLink from '../NavLink';
7 | import Brand from '../Brand';
8 | import SidebarFooter from './SidebarFooter';
9 | import './frame.css';
10 |
11 | const NavItem = (props: any) => {
12 | const { title, eventKey, ...rest } = props;
13 | return (
14 |
15 | {title}
16 |
17 | );
18 | };
19 |
20 | export interface NavItemData {
21 | eventKey: string;
22 | title: string;
23 | icon?: any;
24 | to?: string;
25 | target?: string;
26 | children?: NavItemData[];
27 | }
28 |
29 | export interface FrameProps {
30 | navs: NavItemData[];
31 | children?: React.ReactNode;
32 | }
33 |
34 | const Frame = (props: FrameProps) => {
35 | const { navs } = props;
36 | const [expanded, setExpanded] = useState(true);
37 | const [activeKey, setActiveKey] = useState('1');
38 | const [isMobile] = useMediaQuery('(max-width: 768px)');
39 | const isExpanded = expanded && !isMobile;
40 |
41 | return (
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | {navs.map(item => {
51 | const { children, ...rest } = item;
52 | if (children) {
53 | return (
54 |
60 | {children.map(child => {
61 | return ;
62 | })}
63 |
64 | );
65 | }
66 |
67 | if (rest.target === '_blank') {
68 | return (
69 |
70 | {item.title}
71 |
72 | );
73 | }
74 |
75 | return ;
76 | })}
77 |
78 |
79 | setExpanded(!expanded)} />
80 |
81 |
82 |
83 |
84 | {props.children}
85 |
86 |
87 | );
88 | };
89 |
90 | export default Frame;
91 |
--------------------------------------------------------------------------------
/src/app/(main)/table/members/Cells.tsx:
--------------------------------------------------------------------------------
1 | import { Popover, Whisper, Checkbox, Menu, IconButton, Table, CellProps } from 'rsuite';
2 | import { FiMoreVertical } from 'react-icons/fi';
3 |
4 | const { Cell } = Table;
5 |
6 | export const NameCell = ({ rowData, dataKey, ...props }: CellProps) => {
7 | const speaker = (
8 |
9 |
10 | Name: {rowData.name}
11 |
12 |
13 | Gender: {rowData.gender}
14 |
15 |
16 | City: {rowData.city}
17 |
18 |
19 | Street: {rowData.street}
20 |
21 |
22 | );
23 |
24 | return (
25 |
26 |
27 | {dataKey ? rowData[dataKey] : null}
28 |
29 | |
30 | );
31 | };
32 |
33 | export const ImageCell = ({ rowData, dataKey, ...props }: CellProps) => (
34 |
35 |
46 |
47 |
48 | |
49 | );
50 |
51 | export const CheckCell = ({
52 | rowData,
53 | onChange,
54 | checkedKeys,
55 | dataKey,
56 | ...props
57 | }: Omit, 'onChange'> & {
58 | checkedKeys: number[];
59 | onChange: (value: any, checked: boolean) => void;
60 | }) => (
61 | |
62 |
63 | onChange(value, checked)}
67 | checked={checkedKeys.some(item => item === rowData[dataKey!])}
68 | />
69 |
70 | |
71 | );
72 |
73 | const renderMenu = ({ onClose, left, top, className }: any, ref: any) => {
74 | const handleSelect = (eventKey?: string | number) => {
75 | onClose();
76 | console.log(eventKey);
77 | };
78 | return (
79 |
80 |
81 | Follow
82 | Sponsor
83 | Add to friends
84 | View Profile
85 | Block
86 |
87 |
88 | );
89 | };
90 |
91 | export const ActionCell = (props: any) => {
92 | return (
93 |
94 |
95 | } />
96 |
97 | |
98 | );
99 | };
100 |
--------------------------------------------------------------------------------
/src/app/sign-in/SignIn.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import React from 'react';
4 | import { Form, Button, IconButton, Divider, PasswordInput } from 'rsuite';
5 | import Link from 'next/link';
6 | import GithubIcon from '@rsuite/icons/legacy/Github';
7 | import FacebookIcon from '@rsuite/icons/legacy/Facebook';
8 | import GoogleIcon from '@rsuite/icons/legacy/Google';
9 | import WechatIcon from '@rsuite/icons/legacy/Wechat';
10 |
11 | const SignIn = () => {
12 | return (
13 |
14 |
15 |
16 |
RSUITE
17 |
Welcome to Admin Dashboard
18 |
19 | Build beautiful, modern web applications with our comprehensive React admin template.
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
Sign In
28 |
29 | New here? Create an account
30 |
31 |
32 |
33 |
35 | Username or email address
36 |
37 |
38 |
39 |
40 |
41 | Password
42 |
43 | Forgot password?
44 |
45 |
46 |
51 |
52 |
53 |
54 |
55 | Sign In
56 |
57 |
58 |
59 |
OR
60 |
61 |
62 | }
64 | circle
65 | appearance="subtle"
66 | className="auth-social-btn"
67 | />
68 | }
70 | circle
71 | appearance="subtle"
72 | className="auth-social-btn"
73 | />
74 | }
76 | circle
77 | appearance="subtle"
78 | className="auth-social-btn"
79 | />
80 | }
82 | circle
83 | appearance="subtle"
84 | className="auth-social-btn"
85 | />
86 |
87 |
88 |
89 |
90 |
91 | );
92 | };
93 |
94 | export default SignIn;
95 |
--------------------------------------------------------------------------------
/src/components/Logo/Logo.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Box, BoxProps } from 'rsuite';
3 | import classNames from 'classnames';
4 | import './logo.css';
5 |
6 | interface LogoProps extends BoxProps {
7 | width?: number;
8 | height?: number;
9 | className?: string;
10 | style?: React.CSSProperties;
11 | }
12 |
13 | export default function Logo({ width, height, style, className = '', ...rest }: LogoProps) {
14 | const styles = { width, height, display: 'inline-block', ...style };
15 | return (
16 |
27 |
35 | React Suite
36 |
37 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
66 |
76 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | );
91 | }
92 |
--------------------------------------------------------------------------------
/src/components/PageToolbar.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useState, useRef } from 'react';
4 | import { Affix, Stack, DateRangePicker, IconButton, SelectPicker } from 'rsuite';
5 | import SettingIcon from '@rsuite/icons/Setting';
6 | import {
7 | subDays,
8 | startOfWeek,
9 | endOfWeek,
10 | addDays,
11 | startOfMonth,
12 | endOfMonth,
13 | addMonths
14 | } from 'date-fns';
15 |
16 | interface Range {
17 | label: string;
18 | // A fixed range or a function range that computes a date range from current value
19 | value: [Date, Date] | ((value?: [Date, Date] | null) => [Date, Date]);
20 | placement?: 'top' | 'bottom' | 'left' | 'right';
21 | closeOverlay?: boolean;
22 | appearance?: 'default' | 'primary' | 'link' | 'subtle' | 'ghost';
23 | }
24 |
25 | const predefinedRanges: Range[] = [
26 | {
27 | label: 'Today',
28 | value: [new Date(), new Date()],
29 | placement: 'left'
30 | },
31 | {
32 | label: 'Yesterday',
33 | value: [addDays(new Date(), -1), addDays(new Date(), -1)],
34 | placement: 'left'
35 | },
36 | {
37 | label: 'This week',
38 | value: [startOfWeek(new Date()), endOfWeek(new Date())],
39 | placement: 'left'
40 | },
41 | {
42 | label: 'Last 7 days',
43 | value: [subDays(new Date(), 6), new Date()],
44 | placement: 'left'
45 | },
46 | {
47 | label: 'Last 30 days',
48 | value: [subDays(new Date(), 29), new Date()],
49 | placement: 'left'
50 | },
51 | {
52 | label: 'This month',
53 | value: [startOfMonth(new Date()), new Date()],
54 | placement: 'left'
55 | },
56 | {
57 | label: 'Last month',
58 | value: [startOfMonth(addMonths(new Date(), -1)), endOfMonth(addMonths(new Date(), -1))],
59 | placement: 'left'
60 | },
61 | {
62 | label: 'This year',
63 | value: [new Date(new Date().getFullYear(), 0, 1), new Date()],
64 | placement: 'left'
65 | },
66 | {
67 | label: 'Last year',
68 | value: [new Date(new Date().getFullYear() - 1, 0, 1), new Date(new Date().getFullYear(), 0, 0)],
69 | placement: 'left'
70 | },
71 | {
72 | label: 'All time',
73 | value: [new Date(new Date().getFullYear() - 1, 0, 1), new Date()],
74 | placement: 'left'
75 | },
76 | {
77 | label: 'Last week',
78 | closeOverlay: false,
79 | value: value => {
80 | const [start = new Date()] = value || [];
81 | return [
82 | addDays(startOfWeek(start, { weekStartsOn: 0 }), -7),
83 | addDays(endOfWeek(start, { weekStartsOn: 0 }), -7)
84 | ];
85 | },
86 | appearance: 'default'
87 | },
88 | {
89 | label: 'Next week',
90 | closeOverlay: false,
91 | value: value => {
92 | const [start = new Date()] = value || [];
93 | return [
94 | addDays(startOfWeek(start, { weekStartsOn: 0 }), 7),
95 | addDays(endOfWeek(start, { weekStartsOn: 0 }), 7)
96 | ];
97 | },
98 | appearance: 'default'
99 | }
100 | ];
101 |
102 | const PageToolbar = () => {
103 | const [fixed, setFixed] = useState(false);
104 | const containerRef = useRef(null);
105 |
106 | return (
107 |
108 |
121 |
122 | containerRef.current as HTMLDivElement}
128 | data={[
129 | { label: 'Daily', value: 'Daily' },
130 | { label: 'Weekly', value: 'Weekly' },
131 | { label: 'Monthly', value: 'Monthly' }
132 | ]}
133 | />
134 | containerRef.current as HTMLDivElement}
140 | />
141 |
142 |
143 | } />
144 |
145 |
146 | );
147 | };
148 |
149 | export default PageToolbar;
150 |
--------------------------------------------------------------------------------
/src/app/(main)/dashboard/Dashboard.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 | import dynamic from 'next/dynamic';
3 | import './dashboard-chartist.css';
4 | import './dashboard.css';
5 | import Image from 'next/image';
6 | import { Row, Col, Panel, SegmentedControl } from 'rsuite';
7 |
8 | const BarChart = dynamic(() => import('./BarChart'), { ssr: false });
9 | const PieChart = dynamic(() => import('./PieChart'), { ssr: false });
10 | const DataTable = dynamic(() => import('./DataTable'), { ssr: false });
11 |
12 | const barChartData = [
13 | {
14 | name: 'Web',
15 | data: [
16 | 11, 8, 9, 10, 3, 11, 11, 11, 12, 13, 2, 12, 5, 8, 22, 6, 8, 6, 4, 1, 8, 24, 29, 51, 40, 47,
17 | 23, 26, 50, 26, 22, 27, 46, 47, 81, 46, 40
18 | ]
19 | },
20 | {
21 | name: 'Social',
22 | data: [
23 | 7, 5, 4, 3, 3, 11, 4, 7, 5, 12, 12, 15, 13, 12, 6, 7, 7, 1, 5, 5, 2, 12, 4, 6, 18, 3, 5, 2,
24 | 13, 15, 20, 47, 18, 15, 11, 10, 9
25 | ]
26 | },
27 | {
28 | name: 'Other',
29 | data: [
30 | 4, 9, 11, 7, 8, 3, 6, 5, 5, 4, 6, 4, 11, 10, 3, 6, 7, 5, 2, 8, 4, 9, 9, 2, 6, 7, 5, 1, 8, 3,
31 | 12, 3, 4, 9, 7, 11, 10
32 | ]
33 | }
34 | ];
35 |
36 | const Dashboard = () => {
37 | return (
38 | <>
39 |
40 |
41 |
42 |
49 | Page Views
50 | 281,358
51 |
52 |
53 |
54 |
55 |
62 | Visits
63 | 251,901
64 |
65 |
66 |
67 |
68 |
75 | Unique Visitors
76 | 25,135
77 |
78 |
79 |
80 |
81 |
82 |
83 |
94 | }
95 | data={barChartData}
96 | type="bar"
97 | labels={[
98 | '2022-01-20',
99 | '2022-01-21',
100 | '2022-01-22',
101 | '2022-01-23',
102 | '2022-01-24',
103 | '2022-01-25',
104 | '2022-01-26',
105 | '2022-01-27',
106 | '2022-01-28',
107 | '2022-01-29',
108 | '2022-01-30',
109 | '2022-02-01',
110 | '2022-02-02',
111 | '2022-02-03',
112 | '2022-02-04',
113 | '2022-02-05',
114 | '2022-02-06',
115 | '2022-02-07',
116 | '2022-02-08',
117 | '2022-02-09',
118 | '2022-02-10',
119 | '2022-02-11',
120 | '2022-02-12',
121 | '2022-02-13',
122 | '2022-02-14',
123 | '2022-02-15',
124 | '2022-02-16',
125 | '2022-02-17',
126 | '2022-02-18',
127 | '2022-02-19',
128 | '2022-02-20',
129 | '2022-02-21',
130 | '2022-02-22',
131 | '2022-02-23',
132 | '2022-02-24',
133 | '2022-02-25',
134 | '2022-02-26'
135 | ]}
136 | />
137 |
138 |
139 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
158 |
159 |
160 | >
161 | );
162 | };
163 |
164 | export default Dashboard;
165 |
--------------------------------------------------------------------------------
/src/app/auth.css:
--------------------------------------------------------------------------------
1 | /* Authentication Pages - Modern Split Screen Layout */
2 | .auth-page {
3 | display: flex;
4 | min-height: 100vh;
5 | width: 100%;
6 | background: var(--auth-bg);
7 | }
8 |
9 | /* Left Banner Section */
10 | .auth-banner {
11 | flex: 1;
12 | background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
13 | position: relative;
14 | display: flex;
15 | flex-direction: column;
16 | justify-content: center;
17 | align-items: center;
18 | padding: 60px;
19 | overflow: hidden;
20 | }
21 |
22 | .auth-banner::before {
23 | content: '';
24 | position: absolute;
25 | width: 500px;
26 | height: 500px;
27 | background: rgba(255, 255, 255, 0.1);
28 | border-radius: 50%;
29 | top: -150px;
30 | left: -150px;
31 | }
32 |
33 | .auth-banner::after {
34 | content: '';
35 | position: absolute;
36 | width: 400px;
37 | height: 400px;
38 | background: rgba(255, 255, 255, 0.08);
39 | border-radius: 50%;
40 | bottom: -100px;
41 | right: -100px;
42 | }
43 |
44 | .auth-banner-content {
45 | position: relative;
46 | z-index: 2;
47 | text-align: center;
48 | color: #fff;
49 | }
50 |
51 | .auth-banner-logo {
52 | font-size: 3.5rem;
53 | font-weight: 800;
54 | margin-bottom: 24px;
55 | letter-spacing: -1px;
56 | }
57 |
58 | .auth-banner-title {
59 | font-size: 2rem;
60 | font-weight: 600;
61 | margin-bottom: 16px;
62 | line-height: 1.3;
63 | }
64 |
65 | .auth-banner-subtitle {
66 | font-size: 1.125rem;
67 | opacity: 0.95;
68 | line-height: 1.7;
69 | max-width: 420px;
70 | margin: 0 auto;
71 | }
72 |
73 | /* Right Form Section */
74 | .auth-form-wrapper {
75 | flex: 1;
76 | display: flex;
77 | justify-content: center;
78 | align-items: center;
79 | padding: 40px;
80 | background: var(--auth-form-bg);
81 | }
82 |
83 | .auth-form-container {
84 | width: 100%;
85 | max-width: 440px;
86 | }
87 |
88 | .auth-form-header {
89 | margin-bottom: 48px;
90 | }
91 |
92 | .auth-form-title {
93 | font-size: 2rem;
94 | font-weight: 700;
95 | color: var(--auth-title-color);
96 | margin-bottom: 12px;
97 | }
98 |
99 | .auth-form-subtitle {
100 | font-size: 1rem;
101 | color: var(--auth-subtitle-color);
102 | margin-bottom: 8px;
103 | }
104 |
105 | .auth-form-subtitle a {
106 | color: var(--auth-link-color);
107 | font-weight: 600;
108 | text-decoration: none;
109 | transition: color 0.2s;
110 | }
111 |
112 | .auth-form-subtitle a:hover {
113 | color: var(--auth-link-hover);
114 | }
115 |
116 | /* Form Styling */
117 | .auth-form .rs-form-group {
118 | margin-bottom: 24px;
119 | }
120 |
121 | .auth-form .rs-form-control-label,
122 | .auth-form .rs-form-control-label-wrapper {
123 | font-weight: 500;
124 | color: var(--text-secondary);
125 | margin-bottom: 8px;
126 | }
127 |
128 | .auth-form .rs-input,
129 | .auth-form .rs-input-group {
130 | height: 48px;
131 | font-size: 1rem;
132 | border-radius: 8px;
133 | }
134 |
135 | .auth-form .rs-input {
136 | border: 2px solid var(--auth-input-border);
137 | transition: all 0.2s;
138 | }
139 |
140 | .auth-form .rs-input:focus {
141 | border-color: var(--auth-input-focus-border);
142 | box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
143 | }
144 |
145 | .auth-submit-btn {
146 | height: 52px;
147 | font-size: 1.0625rem;
148 | font-weight: 600;
149 | border-radius: 8px;
150 | margin-top: 8px;
151 | transition: all 0.3s;
152 | }
153 |
154 | .auth-submit-btn:hover {
155 | transform: translateY(-1px);
156 | box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
157 | }
158 |
159 | .auth-divider {
160 | margin: 32px 0;
161 | }
162 |
163 | .auth-divider .rs-divider-inner-text {
164 | color: var(--auth-divider-text);
165 | font-size: 0.875rem;
166 | font-weight: 500;
167 | }
168 |
169 | .auth-social-buttons {
170 | display: flex;
171 | justify-content: center;
172 | gap: 16px;
173 | }
174 |
175 | .auth-social-btn {
176 | border: 2px solid var(--auth-input-border);
177 | transition: all 0.2s;
178 | }
179 |
180 | .auth-social-btn:hover {
181 | border-color: var(--auth-link-color);
182 | background: var(--hover-bg);
183 | transform: translateY(-2px);
184 | }
185 |
186 | .forgot-password-link {
187 | margin-left: 0.5rem;
188 | color: var(--auth-link-color);
189 | font-size: 0.875rem;
190 | font-weight: 500;
191 | text-decoration: none;
192 | transition: color 0.2s;
193 | }
194 |
195 | .forgot-password-link:hover {
196 | color: var(--auth-link-hover);
197 | }
198 |
199 | .auth-checkbox-group {
200 | margin-top: 24px;
201 | margin-bottom: 24px;
202 | }
203 |
204 | .auth-checkbox-group .rs-checkbox {
205 | font-size: 0.9375rem;
206 | color: var(--auth-checkbox-color);
207 | }
208 |
209 | .auth-checkbox-group .rs-btn-link {
210 | padding: 0;
211 | font-size: 0.9375rem;
212 | color: var(--auth-link-color);
213 | font-weight: 500;
214 | }
215 |
216 | .auth-checkbox-group .rs-btn-link:hover {
217 | color: var(--auth-link-hover);
218 | }
219 |
220 | /* Responsive Design */
221 | @media (max-width: 968px) {
222 | .auth-page {
223 | flex-direction: column;
224 | }
225 |
226 | .auth-banner {
227 | min-height: 280px;
228 | padding: 40px 20px;
229 | }
230 |
231 | .auth-banner-logo {
232 | font-size: 2.5rem;
233 | }
234 |
235 | .auth-banner-title {
236 | font-size: 1.5rem;
237 | }
238 |
239 | .auth-banner-subtitle {
240 | font-size: 1rem;
241 | }
242 |
243 | .auth-form-wrapper {
244 | padding: 32px 20px;
245 | }
246 |
247 | .auth-form-container {
248 | max-width: 100%;
249 | }
250 | }
251 |
--------------------------------------------------------------------------------
/src/app/globals.css:
--------------------------------------------------------------------------------
1 | /* Theme CSS Variables */
2 | :root[data-theme='light'],
3 | :root:not([data-theme]) {
4 | --bg-body: #f5f8fa;
5 | --bg-sidebar: #fff;
6 | --bg-panel: #fff;
7 | --text-primary: #272c36;
8 | --text-secondary: #2d3748;
9 | --text-muted: #575757;
10 | --text-tertiary: #718096;
11 | --border-color: #f2f2f5;
12 | --border-secondary: #e2e8f0;
13 | --divider-color: #e5e5ea;
14 | --hover-bg: rgba(0, 0, 0, 0.02);
15 | --active-color: #34c3ff;
16 | --link-color: #3498ff;
17 | --link-hover-color: #2980d9;
18 |
19 | /* Form colors */
20 | --form-label-color: #575757;
21 | --form-border-color: #e2e8f0;
22 | --form-border-focus-color: #667eea;
23 |
24 | /* Chart colors */
25 | --chart-label-color: #eee;
26 | --chart-stroke-color: #eee;
27 | --chart-grid-color: hsla(0, 0%, 100%, 0.2);
28 | --chart-bar-series-1: #206bc4;
29 | --chart-bar-series-2: #79a6dc;
30 | --chart-bar-series-3: #bfe399;
31 | --chart-sparkline-color: #ffffff;
32 | --chart-pie-series-1: #5f71e4;
33 | --chart-pie-series-2: #2dce88;
34 | --chart-pie-series-3: #fa6340;
35 | --chart-pie-series-4: #f5365d;
36 | --chart-pie-series-5: #13cdef;
37 | --chart-magenta-from: #ec407a;
38 | --chart-magenta-to: #d81b60;
39 | --chart-orange-from: #ffa726;
40 | --chart-orange-to: #fb8c00;
41 | --chart-azure-from: #26c6da;
42 | --chart-azure-to: #00acc1;
43 |
44 | /* Dashboard / cards */
45 | --card-bg: var(--rs-card-bg);
46 | --colorful-chart-text: #ffffff;
47 | --colorful-chart-title: rgba(255, 255, 255, 0.5);
48 | --table-bg: var(--rs-card-bg);
49 | --tooltip-text: #575757;
50 |
51 | /* Dashboard gradients */
52 | --bg-gradient-orange-from: #fb6340;
53 | --bg-gradient-orange-to: #fbb140;
54 | --bg-gradient-red-from: #f5365c;
55 | --bg-gradient-red-to: #f56036;
56 | --bg-gradient-green-from: #2dce89;
57 | --bg-gradient-green-to: #2dcecc;
58 | --bg-gradient-blue-from: #11cdef;
59 | --bg-gradient-blue-to: #1171ef;
60 |
61 | /* Toolbar */
62 | --toolbar-shadow-elevated: 0 0 15px 0 rgb(0 0 0 / 10%);
63 |
64 | /* Auth page colors */
65 | --auth-bg: #f5f8fa;
66 | --auth-form-bg: #fff;
67 | --auth-title-color: #1a202c;
68 | --auth-subtitle-color: #718096;
69 | --auth-input-border: #e2e8f0;
70 | --auth-input-focus-border: #667eea;
71 | --auth-link-color: #667eea;
72 | --auth-link-hover: #764ba2;
73 | --auth-divider-text: #a0aec0;
74 | --auth-checkbox-color: #4a5568;
75 | }
76 |
77 | :root[data-theme='dark'] {
78 | --bg-body: var(--rs-gray-900);
79 | --bg-sidebar: #272c36;
80 | --bg-panel: var(--rs-gray-800);
81 | --text-primary: #e8e8e8;
82 | --text-secondary: #d1d5db;
83 | --text-muted: #a0a0a0;
84 | --text-tertiary: #9ca3af;
85 | --border-color: #3a3f4b;
86 | --border-secondary: #4a5568;
87 | --divider-color: #3a3f4b;
88 | --hover-bg: rgba(255, 255, 255, 0.05);
89 | --active-color: #34c3ff;
90 | --link-color: #60a5fa;
91 | --link-hover-color: #93c5fd;
92 |
93 | /* Form colors */
94 | --form-label-color: #d1d5db;
95 | --form-border-color: #4a5568;
96 | --form-border-focus-color: #818cf8;
97 |
98 | /* Chart colors */
99 | --chart-label-color: #d1d5db;
100 | --chart-stroke-color: #d1d5db;
101 | --chart-grid-color: rgba(255, 255, 255, 0.1);
102 | --chart-bar-series-1: #60a5fa;
103 | --chart-bar-series-2: #38bdf8;
104 | --chart-bar-series-3: #4ade80;
105 | --chart-sparkline-color: #ffffff;
106 | --chart-pie-series-1: #818cf8;
107 | --chart-pie-series-2: #22c55e;
108 | --chart-pie-series-3: #fb923c;
109 | --chart-pie-series-4: #f97373;
110 | --chart-pie-series-5: #2dd4bf;
111 | --chart-magenta-from: #ec407a;
112 | --chart-magenta-to: #d81b60;
113 | --chart-orange-from: #f97316;
114 | --chart-orange-to: #ea580c;
115 | --chart-azure-from: #22d3ee;
116 | --chart-azure-to: #06b6d4;
117 |
118 | /* Dashboard / cards */
119 | --card-bg: var(--rs-gray-800);
120 | --colorful-chart-text: #f9fafb;
121 | --colorful-chart-title: rgba(249, 250, 251, 0.7);
122 | --table-bg: var(--rs-gray-800);
123 | --tooltip-text: #e5e7eb;
124 |
125 | /* Dashboard gradients */
126 | --bg-gradient-orange-from: #fb923c;
127 | --bg-gradient-orange-to: #fdba74;
128 | --bg-gradient-red-from: #f97373;
129 | --bg-gradient-red-to: #fb7185;
130 | --bg-gradient-green-from: #22c55e;
131 | --bg-gradient-green-to: #2dd4bf;
132 | --bg-gradient-blue-from: #38bdf8;
133 | --bg-gradient-blue-to: #6366f1;
134 |
135 | /* Toolbar */
136 | --toolbar-shadow-elevated: 0 0 15px 0 rgb(0 0 0 / 40%);
137 |
138 | /* Auth page colors */
139 | --auth-bg: #1a1d24;
140 | --auth-form-bg: #272c36;
141 | --auth-title-color: #e8e8e8;
142 | --auth-subtitle-color: #9ca3af;
143 | --auth-input-border: #4a5568;
144 | --auth-input-focus-border: #818cf8;
145 | --auth-link-color: #818cf8;
146 | --auth-link-hover: #a5b4fc;
147 | --auth-divider-text: #6b7280;
148 | --auth-checkbox-color: #d1d5db;
149 | }
150 |
151 | /* Custom styles */
152 | body {
153 | background: var(--bg-body) !important;
154 | color: var(--text-primary);
155 | }
156 |
157 | .text-muted {
158 | color: var(--text-muted);
159 | }
160 |
161 | .brand {
162 | padding: 10px;
163 | font-size: 16px;
164 | white-space: nowrap;
165 | overflow: hidden;
166 | font-weight: bold;
167 | text-transform: uppercase;
168 |
169 | a {
170 | text-decoration: none;
171 | }
172 | }
173 |
174 | .card {
175 | background: var(--card-bg);
176 | margin-top: 30px;
177 | border-radius: 6px;
178 | }
179 |
180 | .card h3 {
181 | line-height: 22px;
182 | margin-bottom: 20px;
183 | font-size: 18px;
184 | }
185 |
186 | /* Generic page content wrapper */
187 | .page-content {
188 | background: var(--card-bg);
189 | }
190 |
--------------------------------------------------------------------------------
/public/images/pv.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Group 5 Copy
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/src/app/(main)/table/members/DataTable.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useState } from 'react';
4 | import {
5 | Input,
6 | InputGroup,
7 | Table,
8 | Button,
9 | DOMHelper,
10 | Progress,
11 | Checkbox,
12 | Stack,
13 | SelectPicker
14 | } from 'rsuite';
15 | import { FiSearch, FiMoreVertical } from 'react-icons/fi';
16 | import DrawerView from './DrawerView';
17 | import { mockUsers } from '@/data/mock';
18 | import { NameCell, ImageCell, CheckCell, ActionCell } from './Cells';
19 | import './members-table.css';
20 |
21 | const data = mockUsers(20);
22 |
23 | const { Column, HeaderCell, Cell } = Table;
24 | const { getHeight } = DOMHelper;
25 |
26 | const ratingList = Array.from({ length: 5 }).map((_, index) => {
27 | return {
28 | value: index + 1,
29 | label: Array.from({ length: index + 1 })
30 | .map(() => '⭐️')
31 | .join('')
32 | };
33 | });
34 |
35 | type Member = (typeof data)[number];
36 |
37 | const DataTable = () => {
38 | const [showDrawer, setShowDrawer] = useState(false);
39 | const [checkedKeys, setCheckedKeys] = useState([]);
40 | const [sortColumn, setSortColumn] = useState();
41 | const [sortType, setSortType] = useState<'asc' | 'desc' | undefined>();
42 | const [searchKeyword, setSearchKeyword] = useState('');
43 | const [rating, setRating] = useState(null);
44 |
45 | let checked = false;
46 | let indeterminate = false;
47 |
48 | if (checkedKeys.length === data.length) {
49 | checked = true;
50 | } else if (checkedKeys.length === 0) {
51 | checked = false;
52 | } else if (checkedKeys.length > 0 && checkedKeys.length < data.length) {
53 | indeterminate = true;
54 | }
55 |
56 | const handleCheckAll = (_value: unknown, checked: boolean) => {
57 | const keys = checked ? data.map(item => item.id) : [];
58 | setCheckedKeys(keys);
59 | };
60 | const handleCheck = (value: number, checked: boolean) => {
61 | const keys = checked ? [...checkedKeys, value] : checkedKeys.filter(item => item !== value);
62 | setCheckedKeys(keys);
63 | };
64 |
65 | const handleSortColumn = (dataKey: string, sortType?: 'asc' | 'desc') => {
66 | setSortColumn(dataKey as keyof Member);
67 | setSortType(sortType);
68 | };
69 |
70 | const filteredData = () => {
71 | const filtered = data.filter(item => {
72 | if (!item.name.includes(searchKeyword)) {
73 | return false;
74 | }
75 |
76 | if (rating && item.rating !== rating) {
77 | return false;
78 | }
79 |
80 | return true;
81 | });
82 |
83 | if (sortColumn && sortType) {
84 | return filtered.sort((a, b) => {
85 | let x = a[sortColumn] as string | number;
86 | let y = b[sortColumn] as string | number;
87 |
88 | if (typeof x === 'string') {
89 | x = x.charCodeAt(0);
90 | }
91 | if (typeof y === 'string') {
92 | y = y.charCodeAt(0);
93 | }
94 |
95 | if (sortType === 'asc') {
96 | return x - y;
97 | } else {
98 | return y - x;
99 | }
100 | });
101 | }
102 | return filtered;
103 | };
104 |
105 | return (
106 | <>
107 |
108 | setShowDrawer(true)}>
109 | Add Member
110 |
111 |
112 |
113 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
136 |
137 | Id
138 | |
139 |
140 |
141 |
142 |
143 |
144 |
150 |
151 |
152 |
153 |
154 |
155 | Avatar
156 |
157 |
158 |
159 |
160 | Name
161 |
162 |
163 |
164 |
165 | Skill Proficiency
166 |
167 | {rowData => }
168 | |
169 |
170 |
171 |
172 | Rating
173 |
174 | {rowData =>
175 | Array.from({ length: rowData.rating }).map((_, i) => ⭐️ )
176 | }
177 | |
178 |
179 |
180 |
181 | Income
182 | {rowData => `$${rowData.amount}`} |
183 |
184 |
185 |
186 | Email
187 | |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 | setShowDrawer(false)} />
199 | >
200 | );
201 | };
202 |
203 | export default DataTable;
204 |
--------------------------------------------------------------------------------
/src/components/Frame/SidebarFooter.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import React, { useRef, useState, useEffect } from 'react';
4 | import {
5 | Popover,
6 | Whisper,
7 | WhisperInstance,
8 | HStack,
9 | VStack,
10 | Avatar,
11 | Menu,
12 | Divider,
13 | Text,
14 | Sidenav,
15 | SegmentedControl
16 | } from 'rsuite';
17 | import {
18 | BsSun,
19 | BsMoon,
20 | BsDisplay,
21 | BsPersonCircle,
22 | BsGear,
23 | BsQuestionCircle,
24 | BsBoxArrowRight
25 | } from 'react-icons/bs';
26 | import { FiActivity } from 'react-icons/fi';
27 |
28 | interface SidebarFooterProps {
29 | isExpanded: boolean;
30 | onToggle: () => void;
31 | }
32 |
33 | type ThemeMode = 'light' | 'dark' | 'system';
34 |
35 | // User menu popover
36 | const renderUserMenu = (
37 | { onClose, left, top, className }: any,
38 | ref: any,
39 | theme: ThemeMode,
40 | onThemeChange: (value: ThemeMode) => void
41 | ) => {
42 | const handleSelect = (eventKey?: string | number) => {
43 | onClose();
44 | console.log(eventKey);
45 | };
46 |
47 | return (
48 |
49 |
50 |
51 |
52 | Administrator
53 |
54 | admin@example.com
55 |
56 |
57 |
58 |
59 |
60 | {/* Theme Switcher */}
61 |
62 |
63 | THEME
64 |
65 | onThemeChange(value as ThemeMode)}
68 | size="sm"
69 | block
70 | data={[
71 | {
72 | label: (
73 |
74 |
75 | System
76 |
77 | ),
78 | value: 'system'
79 | },
80 | {
81 | label: (
82 |
83 |
84 | Light
85 |
86 | ),
87 | value: 'light'
88 | },
89 | {
90 | label: (
91 |
92 |
93 | Dark
94 |
95 | ),
96 | value: 'dark'
97 | }
98 | ]}
99 | />
100 |
101 |
102 |
103 |
104 | }>
105 | Profile & Account
106 |
107 | }>
108 | Set Status
109 |
110 |
111 | }>
112 | Settings
113 |
114 | }>
115 | Help & Support
116 |
117 |
118 | }>
119 | Sign Out
120 |
121 |
122 |
123 | );
124 | };
125 |
126 | const SidebarFooter: React.FC = ({ isExpanded }) => {
127 | const whisperRef = useRef(null);
128 | const [theme, setTheme] = useState('system');
129 |
130 | // Apply theme on mount and when theme changes
131 | useEffect(() => {
132 | if (typeof window === 'undefined' || typeof document === 'undefined') {
133 | return;
134 | }
135 |
136 | const applyTheme = (mode: ThemeMode) => {
137 | const html = document.documentElement;
138 |
139 | if (mode === 'system') {
140 | // Check system preference
141 | const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
142 | html.setAttribute('data-theme', prefersDark ? 'dark' : 'light');
143 | html.classList.toggle('rs-theme-dark', prefersDark);
144 | } else {
145 | html.setAttribute('data-theme', mode);
146 | html.classList.toggle('rs-theme-dark', mode === 'dark');
147 | }
148 | };
149 |
150 | // Load saved theme from localStorage
151 | const savedTheme =
152 | typeof window !== 'undefined' ? (localStorage.getItem('theme') as ThemeMode | null) : null;
153 | if (savedTheme) {
154 | setTheme(savedTheme);
155 | applyTheme(savedTheme);
156 | } else {
157 | applyTheme('system');
158 | }
159 |
160 | // Listen for system theme changes when in system mode
161 | const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
162 | const handleSystemThemeChange = (e: MediaQueryListEvent) => {
163 | if (theme === 'system') {
164 | const html = document.documentElement;
165 | html.setAttribute('data-theme', e.matches ? 'dark' : 'light');
166 | html.classList.toggle('rs-theme-dark', e.matches);
167 | }
168 | };
169 |
170 | mediaQuery.addEventListener('change', handleSystemThemeChange);
171 | return () => mediaQuery.removeEventListener('change', handleSystemThemeChange);
172 | }, [theme]);
173 |
174 | const handleThemeChange = (newTheme: ThemeMode) => {
175 | setTheme(newTheme);
176 | localStorage.setItem('theme', newTheme);
177 |
178 | const html = document.documentElement;
179 | if (newTheme === 'system') {
180 | const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
181 | html.setAttribute('data-theme', prefersDark ? 'dark' : 'light');
182 | html.classList.toggle('rs-theme-dark', prefersDark);
183 | } else {
184 | html.setAttribute('data-theme', newTheme);
185 | html.classList.toggle('rs-theme-dark', newTheme === 'dark');
186 | }
187 | };
188 |
189 | return (
190 |
191 | renderUserMenu(props, ref, theme, handleThemeChange)}
196 | >
197 |
205 |
206 | {isExpanded && (
207 |
208 |
209 | Administrator
210 |
211 |
212 | admin@example.com
213 |
214 |
215 | )}
216 |
217 |
218 |
219 | );
220 | };
221 |
222 | export default SidebarFooter;
223 |
--------------------------------------------------------------------------------
/public/images/errors/403.svg:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/public/images/uv.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Group 11 Copy
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/src/app/(main)/form/basic/BasicForm.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import {
4 | Form,
5 | RadioGroup,
6 | Radio,
7 | Checkbox,
8 | CheckboxGroup,
9 | DatePicker,
10 | DateRangePicker,
11 | CheckPicker,
12 | SelectPicker,
13 | TagPicker,
14 | Textarea,
15 | TagInput,
16 | MaskedInput,
17 | InputPicker,
18 | NumberInput,
19 | Cascader,
20 | MultiCascader,
21 | Rate,
22 | Uploader,
23 | TreePicker,
24 | CheckTreePicker,
25 | ButtonToolbar,
26 | Button,
27 | Toggle,
28 | AutoComplete,
29 | Divider
30 | } from 'rsuite';
31 | import PageContent from '@/components/PageContent';
32 | import './form-basic.css';
33 |
34 | import { mockTreeData } from '@/data/mock';
35 |
36 | const treeData = mockTreeData({ limits: [2, 3, 3], labels: ['Provincial', 'County', 'Town'] });
37 | const selectData = ['Eugenia', 'Bryan', 'Linda', 'Nancy', 'Lloyd', 'Alice'].map(item => ({
38 | label: item,
39 | value: item
40 | }));
41 |
42 | const BasicForm = () => {
43 | return (
44 |
45 |
46 |
Form Components
47 |
48 | Comprehensive showcase of RSuite form components. For detailed documentation, visit{' '}
49 |
50 | RSuite Form Docs
51 |
52 | .
53 |
54 |
55 |
56 |
313 |
314 | );
315 | };
316 |
317 | export default BasicForm;
318 |
--------------------------------------------------------------------------------
/src/app/(main)/table/members/users.ts:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | id: 1,
4 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/justinrob/128.jpg',
5 | city: 'New Amieshire',
6 | email: 'Leora13@yahoo.com',
7 | firstName: 'Ernest Schuppe',
8 | lastName: 'Schuppe',
9 | street: 'Ratke Port',
10 | zipCode: '17026-3154',
11 | date: '2016-09-23T07:57:40.195Z',
12 | bs: 'global drive functionalities',
13 | catchPhrase: 'Intuitive impactful software',
14 | companyName: 'Lebsack - Nicolas',
15 | words: 'saepe et omnis',
16 | sentence: 'Quos aut sunt id nihil qui.',
17 | stars: 820,
18 | followers: 70
19 | },
20 | {
21 | id: 2,
22 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/thaisselenator_/128.jpg',
23 | city: 'New Gust',
24 | email: 'Mose_Gerhold51@yahoo.com',
25 | firstName: 'Janis',
26 | lastName: 'Vandervort',
27 | street: 'Dickinson Keys',
28 | zipCode: '43767',
29 | date: '2017-03-06T09:59:12.551Z',
30 | bs: 'e-business maximize bandwidth',
31 | catchPhrase: 'De-engineered discrete secured line',
32 | companyName: 'Glover - Hermiston',
33 | words: 'deleniti dolor nihil',
34 | sentence: 'Illo quidem libero corporis laborum.',
35 | stars: 1200,
36 | followers: 170
37 | },
38 | {
39 | id: 3,
40 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/arpitnj/128.jpg',
41 | city: 'Lefflerstad',
42 | email: 'Frieda.Sauer61@gmail.com',
43 | firstName: 'Makenzie',
44 | lastName: 'Bode',
45 | street: 'Legros Divide',
46 | zipCode: '54812',
47 | date: '2016-12-08T13:44:26.557Z',
48 | bs: 'plug-and-play e-enable content',
49 | catchPhrase: 'Ergonomic 6th generation challenge',
50 | companyName: 'Williamson - Kassulke',
51 | words: 'quidem earum magnam',
52 | sentence: 'Nam qui perferendis ut rem vitae saepe.',
53 | stars: 610,
54 | followers: 170
55 | },
56 | {
57 | id: 4,
58 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/brajeshwar/128.jpg',
59 | city: 'East Catalina',
60 | email: 'Eloisa.OHara@hotmail.com',
61 | firstName: 'Ciara',
62 | lastName: 'Towne',
63 | street: 'Schimmel Ramp',
64 | zipCode: '76315-2246',
65 | date: '2016-07-19T12:54:30.994Z',
66 | bs: 'extensible innovate e-business',
67 | catchPhrase: 'Upgradable local model',
68 | companyName: 'Hilpert, Eichmann and Brown',
69 | words: 'exercitationem rerum sit',
70 | sentence: 'Qui rerum ipsa atque qui.',
71 | stars: 5322,
72 | followers: 170
73 | },
74 | {
75 | id: 5,
76 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/dev_essentials/128.jpg',
77 | city: 'Ritchieborough',
78 | email: 'Brisa46@hotmail.com',
79 | firstName: 'Suzanne',
80 | lastName: 'Wolff',
81 | street: 'Lemuel Radial',
82 | zipCode: '88870-3897',
83 | date: '2017-02-23T17:11:53.875Z',
84 | bs: 'back-end orchestrate networks',
85 | catchPhrase: 'Exclusive human-resource knowledge base',
86 | companyName: 'Mayer - Considine',
87 | words: 'voluptatum tempore at',
88 | sentence: 'Enim quia deleniti molestiae aut.',
89 | stars: 852,
90 | followers: 770
91 | },
92 | {
93 | id: 6,
94 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/petrangr/128.jpg',
95 | city: 'Lake Emery',
96 | email: 'Cody.Schultz56@gmail.com',
97 | firstName: 'Alessandra',
98 | lastName: 'Feeney',
99 | street: 'Mosciski Estate',
100 | zipCode: '81514',
101 | date: '2016-06-30T05:23:18.734Z',
102 | bs: 'sexy evolve technologies',
103 | catchPhrase: 'Virtual hybrid throughput',
104 | companyName: 'Nikolaus and Sons',
105 | words: 'alias minus repudiandae',
106 | sentence: 'Sed qui eius excepturi sunt voluptates.',
107 | stars: 3209,
108 | followers: 2780
109 | },
110 | {
111 | id: 7,
112 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/knilob/128.jpg',
113 | city: 'East Dejuan',
114 | email: 'Enrico_Beer@yahoo.com',
115 | firstName: 'Margret',
116 | lastName: 'Heller',
117 | street: 'Gunner Drive',
118 | zipCode: '17423-9317',
119 | date: '2017-03-13T21:09:47.253Z',
120 | bs: 'wireless morph synergies',
121 | catchPhrase: 'Profit-focused radical help-desk',
122 | companyName: 'Corwin, Maggio and Wintheiser',
123 | words: 'temporibus possimus neque',
124 | sentence: 'Eum amet ea non natus qui assumenda illo officia qui.',
125 | stars: 9920,
126 | followers: 570
127 | },
128 | {
129 | id: 8,
130 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/tom_even/128.jpg',
131 | city: 'Schummtown',
132 | email: 'Mitchel.Herman@yahoo.com',
133 | firstName: 'Emiliano',
134 | lastName: 'Moore',
135 | street: 'Maria Junctions',
136 | zipCode: '33930-7081',
137 | date: '2016-03-27T07:26:57.345Z',
138 | bs: 'customized integrate e-tailers',
139 | catchPhrase: 'Total system-worthy contingency',
140 | companyName: 'Gulgowski - Botsford',
141 | words: 'deleniti ipsa hic',
142 | sentence: 'Ducimus id quaerat neque.',
143 | stars: 3820,
144 | followers: 880
145 | },
146 | {
147 | id: 9,
148 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/chandlervdw/128.jpg',
149 | city: 'Gilberthaven',
150 | email: 'Gaylord_Reichel16@yahoo.com',
151 | firstName: 'Alessandra',
152 | lastName: 'Smith',
153 | street: 'Kali Spurs',
154 | zipCode: '01370',
155 | date: '2017-01-24T22:11:53.835Z',
156 | bs: 'extensible repurpose action-items',
157 | catchPhrase: 'Virtual dedicated definition',
158 | companyName: 'Maggio LLC',
159 | words: 'libero unde est',
160 | sentence: 'Non adipisci hic laboriosam et qui laudantium aspernatur.',
161 | stars: 330,
162 | followers: 590
163 | },
164 | {
165 | id: 10,
166 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/mwarkentin/128.jpg',
167 | city: 'Felicitychester',
168 | email: 'Eileen48@gmail.com',
169 | firstName: 'Eldridge',
170 | lastName: 'Bins',
171 | street: 'Casper Squares',
172 | zipCode: '80025-1552',
173 | date: '2016-07-20T05:59:45.630Z',
174 | bs: 'cutting-edge expedite partnerships',
175 | catchPhrase: 'Organic user-facing functionalities',
176 | companyName: 'Leffler, Cummerata and Price',
177 | words: 'sed exercitationem quas',
178 | sentence: 'Voluptas dolorem quasi aspernatur.',
179 | stars: 923,
180 | followers: 704
181 | },
182 | {
183 | id: 11,
184 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/gipsy_raf/128.jpg',
185 | city: 'Caleighhaven',
186 | email: 'Rico_Nolan@hotmail.com',
187 | firstName: 'Claude',
188 | lastName: 'Hermiston',
189 | street: 'Bode Pine',
190 | zipCode: '76773',
191 | date: '2017-03-13T08:02:41.211Z',
192 | bs: 'back-end innovate infomediaries',
193 | catchPhrase: 'Stand-alone global customer loyalty',
194 | companyName: 'Heller, Rosenbaum and Lockman',
195 | words: 'ut quia ut',
196 | sentence: 'Eos consequatur magni incidunt.',
197 | stars: 421,
198 | followers: 403
199 | },
200 | {
201 | id: 12,
202 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/knilob/128.jpg',
203 | city: 'Herzogmouth',
204 | email: 'Dawn_Metz@yahoo.com',
205 | firstName: 'Clarabelle',
206 | lastName: 'Ankunding',
207 | street: 'Nolan Summit',
208 | zipCode: '04355',
209 | date: '2016-07-09T09:07:34.744Z',
210 | bs: 'granular deliver relationships',
211 | catchPhrase: 'Multi-lateral zero defect analyzer',
212 | companyName: 'Mante, Oberbrunner and Collins',
213 | words: 'eos fuga repellat',
214 | sentence: 'Cum corporis molestias quia.',
215 | stars: 8203,
216 | followers: 704
217 | },
218 | {
219 | id: 13,
220 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/kirangopal/128.jpg',
221 | city: 'Eulaliabury',
222 | email: 'Ron.Franecki@gmail.com',
223 | firstName: 'Hubert',
224 | lastName: 'Boehm',
225 | street: 'Anastacio Springs',
226 | zipCode: '91444',
227 | date: '2016-04-22T16:37:24.331Z',
228 | bs: 'one-to-one transition methodologies',
229 | catchPhrase: 'Switchable asymmetric function',
230 | companyName: 'Greenholt, Homenick and Considine',
231 | words: 'sed incidunt quo',
232 | sentence: 'Sed adipisci aliquam ut eius ut ipsa consequatur.',
233 | stars: 8209,
234 | followers: 909
235 | },
236 | {
237 | id: 14,
238 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/kerem/128.jpg',
239 | city: 'East Alice',
240 | email: 'Hayley52@yahoo.com',
241 | firstName: 'Vladimir',
242 | lastName: 'Breitenberg',
243 | street: 'Lula Port',
244 | zipCode: '04635',
245 | date: '2016-09-26T01:25:23.057Z',
246 | bs: 'virtual monetize communities',
247 | catchPhrase: 'Mandatory user-facing methodology',
248 | companyName: 'Kshlerin - Pfeffer',
249 | words: 'eaque enim unde',
250 | sentence: 'Sed voluptas fugiat nihil delectus architecto et voluptatibus quis voluptas.',
251 | stars: 8251,
252 | followers: 178
253 | },
254 | {
255 | id: 15,
256 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/layerssss/128.jpg',
257 | city: 'East Frankie',
258 | email: 'Duane.Rempel@hotmail.com',
259 | firstName: 'Haylee',
260 | lastName: 'Purdy',
261 | street: 'Dena Walk',
262 | zipCode: '94111-0802',
263 | date: '2016-11-26T16:36:38.472Z',
264 | bs: 'enterprise drive users',
265 | catchPhrase: 'Customizable non-volatile paradigm',
266 | companyName: 'Lemke, Mitchell and Harber',
267 | words: 'dolores ipsum earum',
268 | sentence: 'Nemo molestiae ad sit cupiditate neque.',
269 | stars: 3099,
270 | followers: 707
271 | },
272 | {
273 | id: 16,
274 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/dreizle/128.jpg',
275 | city: 'New Kendall',
276 | email: 'Eddie_Bartell@hotmail.com',
277 | firstName: 'Herminia',
278 | lastName: 'Altenwerth',
279 | street: 'Kshlerin Cape',
280 | zipCode: '86614-9727',
281 | date: '2016-09-28T19:50:18.308Z',
282 | bs: 'cutting-edge target models',
283 | catchPhrase: 'Triple-buffered fault-tolerant concept',
284 | companyName: 'Gislason - Nicolas',
285 | words: 'perferendis magnam minima',
286 | sentence: 'Fuga in dolorem vel eligendi deserunt voluptatem.',
287 | stars: 8491,
288 | followers: 463
289 | },
290 | {
291 | id: 17,
292 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/nessoila/128.jpg',
293 | city: 'Port Whitney',
294 | email: 'Josephine_Legros@yahoo.com',
295 | firstName: 'Erick',
296 | lastName: 'Klein',
297 | street: 'Megane Cliffs',
298 | zipCode: '42168',
299 | date: '2016-04-02T05:03:42.377Z',
300 | bs: 'user-centric leverage experiences',
301 | catchPhrase: 'Centralized systematic parallelism',
302 | companyName: 'Olson and Sons',
303 | words: 'facere est in',
304 | sentence: 'Ducimus aliquid ut.',
305 | stars: 9820,
306 | followers: 670
307 | },
308 | {
309 | id: 18,
310 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/mrebay007/128.jpg',
311 | city: 'West Meda',
312 | email: 'Jared.Hudson@hotmail.com',
313 | firstName: 'Lisandro',
314 | lastName: 'Barton',
315 | street: 'Torrance Union',
316 | zipCode: '19477',
317 | date: '2016-08-01T14:24:45.209Z',
318 | bs: 'open-source exploit markets',
319 | catchPhrase: 'Open-source impactful framework',
320 | companyName: 'Volkman and Sons',
321 | words: 'a tempore hic',
322 | sentence: 'Quod veniam nemo impedit mollitia.',
323 | stars: 1220,
324 | followers: 708
325 | },
326 | {
327 | id: 19,
328 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/brenton_clarke/128.jpg',
329 | city: 'Darrenport',
330 | email: 'Delpha.Tromp9@yahoo.com',
331 | firstName: 'Ashton',
332 | lastName: 'Daugherty',
333 | street: 'Hermann Port',
334 | zipCode: '25133-9181',
335 | date: '2016-07-29T09:49:39.424Z',
336 | bs: 'wireless optimize deliverables',
337 | catchPhrase: 'Ergonomic human-resource algorithm',
338 | companyName: 'Grady LLC',
339 | words: 'libero ut repellat',
340 | sentence: 'Vel quod ullam.',
341 | stars: 420,
342 | followers: 30
343 | },
344 | {
345 | id: 20,
346 | avartar: 'https://s3.amazonaws.com/uifaces/faces/twitter/josep_martins/128.jpg',
347 | city: 'Janiyahaven',
348 | email: 'Ariel.Maggio9@yahoo.com',
349 | firstName: 'Cassandra',
350 | lastName: 'Schmitt',
351 | street: 'Windler Lodge',
352 | zipCode: '87582-2944',
353 | date: '2017-01-21T12:35:27.741Z',
354 | bs: 'holistic cultivate relationships',
355 | catchPhrase: 'Enterprise-wide system-worthy data-warehouse',
356 | companyName: 'Ankunding Group',
357 | words: 'blanditiis voluptates repellat',
358 | sentence: 'Non quis non dignissimos sit rerum voluptatem culpa quibusdam.',
359 | stars: 20,
360 | followers: 188
361 | }
362 | ];
363 |
--------------------------------------------------------------------------------
/public/images/vv.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Group 6 Copy
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/public/images/errors/500.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 | Group
4 | Created with Sketch.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------