├── .DS_Store
├── .gitignore
├── README.md
├── components.json
├── eslint.config.js
├── index.html
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
└── vite.svg
├── src
├── .DS_Store
├── App.tsx
├── apis
│ ├── instances
│ │ ├── public-api.ts
│ │ └── secure-api.ts
│ ├── queries
│ │ ├── category.ts
│ │ ├── keys.ts
│ │ └── product.ts
│ └── services
│ │ ├── category.ts
│ │ └── product.ts
├── assets
│ ├── .DS_Store
│ ├── lotties
│ │ ├── .DS_Store
│ │ └── cat.json
│ ├── react.svg
│ └── translations
│ │ ├── en.json
│ │ └── mm.json
├── components
│ ├── .DS_Store
│ ├── charts
│ │ ├── chart-area-axes.tsx
│ │ ├── chart-area-default.tsx
│ │ ├── chart-area-gradient.tsx
│ │ ├── chart-area-icons.tsx
│ │ ├── chart-area-interactive.tsx
│ │ ├── chart-area-legend.tsx
│ │ ├── chart-area-linear.tsx
│ │ ├── chart-area-stacked-expand.tsx
│ │ ├── chart-area-stacked.tsx
│ │ ├── chart-area-step.tsx
│ │ ├── chart-bar-active.tsx
│ │ ├── chart-bar-default.tsx
│ │ ├── chart-bar-horizontal.tsx
│ │ ├── chart-bar-label-custom.tsx
│ │ ├── chart-bar-label.tsx
│ │ ├── chart-bar-mixed.tsx
│ │ ├── chart-bar-multiple.tsx
│ │ ├── chart-bar-negative.tsx
│ │ ├── chart-bar-stacked.tsx
│ │ ├── chart-line-default.tsx
│ │ ├── chart-line-dots-colors.tsx
│ │ ├── chart-line-dots-custom.tsx
│ │ ├── chart-line-dots.tsx
│ │ ├── chart-line-interactive.tsx
│ │ ├── chart-line-label-custom.tsx
│ │ ├── chart-line-label.tsx
│ │ ├── chart-line-linear.tsx
│ │ ├── chart-line-multiple.tsx
│ │ ├── chart-line-step.tsx
│ │ ├── chart-pie-donut-active.tsx
│ │ ├── chart-pie-donut-text.tsx
│ │ ├── chart-pie-donut.tsx
│ │ ├── chart-pie-interactive.tsx
│ │ ├── chart-pie-label-custom.tsx
│ │ ├── chart-pie-label-list.tsx
│ │ ├── chart-pie-label.tsx
│ │ ├── chart-pie-legend.tsx
│ │ ├── chart-pie-separator-none.tsx
│ │ ├── chart-pie-simple.tsx
│ │ ├── chart-pie-stacked.tsx
│ │ ├── chart-radar-default.tsx
│ │ ├── chart-radar-dots.tsx
│ │ ├── chart-radar-grid-circle-fill.tsx
│ │ ├── chart-radar-grid-circle-no-lines.tsx
│ │ ├── chart-radar-grid-circle.tsx
│ │ ├── chart-radar-grid-custom.tsx
│ │ ├── chart-radar-grid-fill.tsx
│ │ ├── chart-radar-grid-none.tsx
│ │ ├── chart-radar-icons.tsx
│ │ ├── chart-radar-label-custom.tsx
│ │ ├── chart-radar-legend.tsx
│ │ ├── chart-radar-lines-only.tsx
│ │ ├── chart-radar-multiple.tsx
│ │ ├── chart-radar-radius.tsx
│ │ ├── chart-radial-grid.tsx
│ │ ├── chart-radial-label.tsx
│ │ ├── chart-radial-shape.tsx
│ │ ├── chart-radial-simple.tsx
│ │ ├── chart-radial-stacked.tsx
│ │ ├── chart-radial-text.tsx
│ │ ├── chart-tooltip-advanced.tsx
│ │ ├── chart-tooltip-default.tsx
│ │ ├── chart-tooltip-formatter.tsx
│ │ ├── chart-tooltip-icons.tsx
│ │ ├── chart-tooltip-indicator-line.tsx
│ │ ├── chart-tooltip-indicator-none.tsx
│ │ ├── chart-tooltip-label-custom.tsx
│ │ ├── chart-tooltip-label-formatter.tsx
│ │ └── chart-tooltip-label-none.tsx
│ ├── commons
│ │ ├── between.tsx
│ │ ├── center.tsx
│ │ ├── lang-dropdown.tsx
│ │ ├── logo.tsx
│ │ ├── page-title.tsx
│ │ └── text.tsx
│ ├── data-table
│ │ ├── data-table-column-header.tsx
│ │ ├── data-table-faceted-filter.tsx
│ │ ├── data-table-loader.tsx
│ │ ├── data-table-pagination.tsx
│ │ ├── data-table-view-options.tsx
│ │ └── data-table.tsx
│ ├── inputs
│ │ ├── checkbox-input.tsx
│ │ ├── checkgroup-Input.tsx
│ │ ├── date-input.tsx
│ │ ├── password-input.tsx
│ │ ├── radio-input.tsx
│ │ ├── search-input.tsx
│ │ ├── select-input.tsx
│ │ ├── text-input.tsx
│ │ └── textarea-input.tsx
│ ├── loaders
│ │ └── page-loader.tsx
│ ├── modals
│ │ ├── demo.tsx
│ │ ├── idle-confirmation.tsx
│ │ └── logout-confirmation.tsx
│ ├── selects
│ │ └── category-select.tsx
│ ├── theme
│ │ └── theme-provider.tsx
│ └── ui
│ │ ├── avatar.tsx
│ │ ├── badge.tsx
│ │ ├── breadcrumb.tsx
│ │ ├── button.tsx
│ │ ├── calendar.tsx
│ │ ├── card.tsx
│ │ ├── chart.tsx
│ │ ├── checkbox.tsx
│ │ ├── command.tsx
│ │ ├── dialog.tsx
│ │ ├── dropdown-menu.tsx
│ │ ├── form.tsx
│ │ ├── input.tsx
│ │ ├── label.tsx
│ │ ├── pagination.tsx
│ │ ├── popover.tsx
│ │ ├── radio-group.tsx
│ │ ├── select.tsx
│ │ ├── separator.tsx
│ │ ├── sheet.tsx
│ │ ├── skeleton.tsx
│ │ ├── slider.tsx
│ │ ├── sonner.tsx
│ │ ├── table.tsx
│ │ ├── tabs.tsx
│ │ ├── textarea.tsx
│ │ └── tooltip.tsx
├── configs
│ ├── menus.tsx
│ ├── routes.tsx
│ └── vars.tsx
├── helpers
│ └── form-schemas-validators.ts
├── hooks
│ ├── use-auth-operations.ts
│ ├── use-auth.ts
│ ├── use-report.ts
│ ├── use-unauth.ts
│ └── use-url-query.ts
├── i18n.ts
├── index.css
├── layouts
│ ├── auth
│ │ ├── auth-layout.tsx
│ │ └── components
│ │ │ ├── header.tsx
│ │ │ └── index.ts
│ ├── dashboard
│ │ ├── components
│ │ │ ├── header.tsx
│ │ │ ├── index.ts
│ │ │ ├── sidebar-footer.tsx
│ │ │ ├── sidebar-header.tsx
│ │ │ ├── sidebar-item.tsx
│ │ │ └── sidebar.tsx
│ │ └── dashboard-layout.tsx
│ └── root
│ │ └── root-layout.tsx
├── lib
│ └── utils.ts
├── main.tsx
├── pages
│ ├── .DS_Store
│ ├── charts
│ │ ├── .DS_Store
│ │ └── charts-page.tsx
│ ├── dashboard
│ │ ├── components
│ │ │ └── recent-sales.tsx
│ │ └── dashboard-page.tsx
│ ├── error-pages
│ │ ├── 404-page.tsx
│ │ ├── 500-page.tsx
│ │ └── components
│ │ │ └── Error.tsx
│ ├── form
│ │ ├── components
│ │ │ └── FormWithReusableInputs.tsx
│ │ ├── form-page.tsx
│ │ ├── mock-data
│ │ │ └── mock-data.ts
│ │ └── schemas
│ │ │ └── normal-form-schema.ts
│ ├── index.ts
│ ├── login
│ │ ├── login-page.tsx
│ │ └── schemas
│ │ │ └── login-schema.ts
│ ├── modals
│ │ ├── components
│ │ │ ├── ModalCard.tsx
│ │ │ └── ToastCard.tsx
│ │ ├── mock-data
│ │ │ ├── modals.ts
│ │ │ └── toasts.ts
│ │ └── modals-page.tsx
│ └── table
│ │ ├── components
│ │ ├── columns.tsx
│ │ ├── row-actions.tsx
│ │ └── tool-bar.tsx
│ │ ├── create-page.tsx
│ │ ├── list-page.tsx
│ │ ├── mock-data
│ │ └── mock-data.ts
│ │ └── schemas
│ │ └── normal-form-schema.ts
├── stores
│ └── user-preference.ts
├── types
│ └── global.d.ts
└── vite-env.d.ts
├── tailwind.config.js
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinPyaeKyaw/shadcn-admin-starter-template/965735f31f0d52136bc1b4da672592de19175f38/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 | node_modules
3 | build
4 | dist
--------------------------------------------------------------------------------
/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "new-york",
4 | "rsc": false,
5 | "tsx": true,
6 | "tailwind": {
7 | "config": "tailwind.config.js",
8 | "css": "src/index.css",
9 | "baseColor": "neutral",
10 | "cssVariables": true,
11 | "prefix": ""
12 | },
13 | "aliases": {
14 | "components": "@components",
15 | "utils": "@lib/utils",
16 | "ui": "@components/ui",
17 | "lib": "@lib",
18 | "hooks": "@/hooks"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import js from "@eslint/js";
2 | import globals from "globals";
3 | import reactHooks from "eslint-plugin-react-hooks";
4 | import reactRefresh from "eslint-plugin-react-refresh";
5 | import tseslint from "typescript-eslint";
6 |
7 | export default tseslint.config(
8 | { ignores: ["dist"] },
9 | {
10 | extends: [js.configs.recommended, ...tseslint.configs.recommended],
11 | files: ["**/*.{ts,tsx}"],
12 | languageOptions: {
13 | ecmaVersion: 2020,
14 | globals: globals.browser,
15 | },
16 | plugins: {
17 | "react-hooks": reactHooks,
18 | "react-refresh": reactRefresh,
19 | },
20 | rules: {
21 | ...reactHooks.configs.recommended.rules,
22 | "react-refresh/only-export-components": [
23 | "warn",
24 | { allowConstantExport: true },
25 | ],
26 | "@typescript-eslint/no-explicit-any": "off",
27 | },
28 | }
29 | );
30 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "shadcn-admin-portal-template",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc -b && vite build",
9 | "lint": "eslint .",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@hookform/resolvers": "^3.9.0",
14 | "@radix-ui/react-avatar": "^1.1.1",
15 | "@radix-ui/react-checkbox": "^1.1.1",
16 | "@radix-ui/react-dialog": "^1.1.1",
17 | "@radix-ui/react-dropdown-menu": "^2.1.1",
18 | "@radix-ui/react-icons": "^1.3.0",
19 | "@radix-ui/react-label": "^2.1.0",
20 | "@radix-ui/react-popover": "^1.1.1",
21 | "@radix-ui/react-radio-group": "^1.2.0",
22 | "@radix-ui/react-select": "^2.1.1",
23 | "@radix-ui/react-separator": "^1.1.0",
24 | "@radix-ui/react-slider": "^1.2.0",
25 | "@radix-ui/react-slot": "^1.1.0",
26 | "@radix-ui/react-tabs": "^1.1.0",
27 | "@radix-ui/react-toast": "^1.2.1",
28 | "@radix-ui/react-tooltip": "^1.1.2",
29 | "@saimin/react-modal-manager": "^1.0.9",
30 | "@tanstack/react-query": "^5.56.2",
31 | "@tanstack/react-table": "^8.20.5",
32 | "axios": "^1.7.7",
33 | "class-variance-authority": "^0.7.0",
34 | "clsx": "^2.1.1",
35 | "cmdk": "^1.0.0",
36 | "date-fns": "^3.6.0",
37 | "i18next": "^23.15.1",
38 | "js-cookie": "^3.0.5",
39 | "lottie-react": "^2.4.0",
40 | "lucide-react": "^0.438.0",
41 | "next-themes": "^0.3.0",
42 | "react": "^18.3.1",
43 | "react-day-picker": "^8.10.1",
44 | "react-dom": "^18.3.1",
45 | "react-hook-form": "^7.53.0",
46 | "react-i18next": "^15.0.1",
47 | "react-idle-timer": "^5.7.2",
48 | "react-router-dom": "^6.26.1",
49 | "recharts": "^2.13.0-alpha.5",
50 | "sonner": "^1.5.0",
51 | "tailwind-merge": "^2.5.2",
52 | "tailwindcss-animate": "^1.0.7",
53 | "xlsx": "^0.18.5",
54 | "zod": "^3.23.8",
55 | "zustand": "^4.5.5"
56 | },
57 | "devDependencies": {
58 | "@eslint/js": "^9.9.0",
59 | "@types/js-cookie": "^3.0.6",
60 | "@types/node": "^22.5.2",
61 | "@types/react": "^18.3.3",
62 | "@types/react-dom": "^18.3.0",
63 | "@vitejs/plugin-react": "^4.3.1",
64 | "autoprefixer": "^10.4.20",
65 | "eslint": "^9.9.0",
66 | "eslint-plugin-react-hooks": "^5.1.0-rc.0",
67 | "eslint-plugin-react-refresh": "^0.4.9",
68 | "globals": "^15.9.0",
69 | "postcss": "^8.4.44",
70 | "tailwindcss": "^3.4.10",
71 | "typescript": "^5.5.3",
72 | "typescript-eslint": "^8.0.1",
73 | "vite": "^5.4.1"
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinPyaeKyaw/shadcn-admin-starter-template/965735f31f0d52136bc1b4da672592de19175f38/src/.DS_Store
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { ThemeProvider } from "@components/theme/theme-provider";
2 | import { Toaster } from "@components/ui/sonner";
3 | import { router } from "@configs/routes";
4 | import { RouterProvider } from "react-router-dom";
5 | import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
6 |
7 | const queryClient = new QueryClient();
8 |
9 | function App() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 | );
18 | }
19 |
20 | export default App;
21 |
--------------------------------------------------------------------------------
/src/apis/instances/public-api.ts:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | const publicApi = axios.create({
4 | baseURL: import.meta.env.VITE_API_URL,
5 | timeout: 1000,
6 | });
7 |
8 | // Add a request interceptor
9 | publicApi.interceptors.request.use(
10 | function (config) {
11 | console.log("public request");
12 | // Do something before request is sent
13 | return config;
14 | },
15 | function (error) {
16 | // Do something with request error
17 | return Promise.reject(error);
18 | }
19 | );
20 |
21 | // Add a response interceptor
22 | publicApi.interceptors.response.use(
23 | function (response) {
24 | console.log("public response");
25 | // Any status code that lie within the range of 2xx cause this function to trigger
26 | // Do something with response data
27 | return response;
28 | },
29 | function (error) {
30 | // Any status codes that falls outside the range of 2xx cause this function to trigger
31 | // Do something with response error
32 | return Promise.reject(error);
33 | }
34 | );
35 |
36 | export default publicApi;
37 |
--------------------------------------------------------------------------------
/src/apis/instances/secure-api.ts:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | const secureApi = axios.create({
4 | baseURL: import.meta.env.VITE_API_URL,
5 | timeout: 1000,
6 | });
7 |
8 | // Add a request interceptor
9 | secureApi.interceptors.request.use(
10 | function (config) {
11 | console.log("secure request");
12 | // Do something before request is sent
13 | return config;
14 | },
15 | function (error) {
16 | // Do something with request error
17 | return Promise.reject(error);
18 | }
19 | );
20 |
21 | // Add a response interceptor
22 | secureApi.interceptors.response.use(
23 | function (response) {
24 | console.log("secure response");
25 | // Any status code that lie within the range of 2xx cause this function to trigger
26 | // Do something with response data
27 | return response;
28 | },
29 | function (error) {
30 | // Any status codes that falls outside the range of 2xx cause this function to trigger
31 | // Do something with response error
32 | return Promise.reject(error);
33 | }
34 | );
35 |
36 | export default secureApi;
37 |
--------------------------------------------------------------------------------
/src/apis/queries/category.ts:
--------------------------------------------------------------------------------
1 | import { useQuery } from "@tanstack/react-query";
2 | import { productKeys } from "./keys";
3 | import { getAllProductCategories } from "@apis/services/category";
4 |
5 | export function useGetAllProductCategories() {
6 | return useQuery({
7 | queryKey: productKeys.all,
8 | queryFn: () => getAllProductCategories(),
9 | select: (data) =>
10 | data.data.map((d: Record) => ({
11 | value: d.slug,
12 | label: d.name,
13 | })),
14 | });
15 | }
16 |
--------------------------------------------------------------------------------
/src/apis/queries/keys.ts:
--------------------------------------------------------------------------------
1 | export const productKeys = {
2 | all: ["product"] as const,
3 | detail: (id: string) => [...productKeys.all, id] as const,
4 | filters: (filters: Record) => [...productKeys.all, ...Object.values(filters)] as const,
5 | };
6 |
7 | export const categoryKeys = {
8 | all: ["category"] as const,
9 | detail: (id: string) => [...categoryKeys.all, id] as const,
10 | filters: (filters: Record) => [...categoryKeys.all, ...Object.values(filters)] as const,
11 | };
12 |
--------------------------------------------------------------------------------
/src/apis/queries/product.ts:
--------------------------------------------------------------------------------
1 | import { getAllProducts } from "@apis/services/product";
2 | import { useQuery } from "@tanstack/react-query";
3 | import { productKeys } from "./keys";
4 |
5 | export function useGetAllProducts(
6 | filters: Record,
7 | enabled: boolean = true
8 | ) {
9 | return useQuery({
10 | queryKey: productKeys.filters(filters),
11 | queryFn: () => getAllProducts(filters),
12 | enabled,
13 | });
14 | }
15 |
--------------------------------------------------------------------------------
/src/apis/services/category.ts:
--------------------------------------------------------------------------------
1 | import publicApi from "@apis/instances/public-api";
2 |
3 | export function getAllProductCategories() {
4 | return publicApi.get("/products/categories");
5 | }
6 |
--------------------------------------------------------------------------------
/src/apis/services/product.ts:
--------------------------------------------------------------------------------
1 | import publicApi from "@apis/instances/public-api";
2 |
3 | export function getAllProducts(filters?: Record) {
4 | return publicApi.get("/products", {
5 | params: filters
6 | });
7 | }
--------------------------------------------------------------------------------
/src/assets/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinPyaeKyaw/shadcn-admin-starter-template/965735f31f0d52136bc1b4da672592de19175f38/src/assets/.DS_Store
--------------------------------------------------------------------------------
/src/assets/lotties/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinPyaeKyaw/shadcn-admin-starter-template/965735f31f0d52136bc1b4da672592de19175f38/src/assets/lotties/.DS_Store
--------------------------------------------------------------------------------
/src/assets/translations/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Welcome",
3 | "sidebar": {
4 | "dashboard": "Dashboard",
5 | "form": "Form",
6 | "table": "Table",
7 | "charts": "Charts",
8 | "calendar": "Calendar",
9 | "errPages": "Error Pages",
10 | "modals": "Modals"
11 | },
12 | "login": {
13 | "loginHere": "Login Here",
14 | "username": "Username",
15 | "enterUsername": "Enter Username",
16 | "password": "Password",
17 | "enterPassword": "Enter Password",
18 | "login": "Login"
19 | },
20 | "form": {
21 | "pageTitle": "Customizable & Reusable Form Components",
22 | "pageDesc": "Easily create dynamic, scalable forms with customizable, reusable components. Simplify development with built-in validation, accessibility, and flexible styling options for any project."
23 | },
24 | "table": {
25 | "pageTitle": "Customizable & Reusable Table Components",
26 | "pageDesc": "Easily create dynamic, scalable forms with customizable, reusable components. Simplify development with built-in validation, accessibility, and flexible styling options for any project."
27 | },
28 | "modal": {
29 | "pageTitle": "Customizable & Reusable Modal Components",
30 | "pageDesc": "Easily create dynamic, scalable forms with customizable, reusable components. Simplify development with built-in validation, accessibility, and flexible styling options for any project."
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/assets/translations/mm.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "ကြိုဆိုပါတယ်ဗျာ",
3 | "sidebar": {
4 | "dashboard": "ဒက်ရှိဘုတ်",
5 | "form": "ဖောင်",
6 | "table": "ဇယားကွက်",
7 | "charts": "ဇယားများ",
8 | "calendar": "ပြက္ခဒိန်",
9 | "errPages": "အမှားစာမျက်နှာများ",
10 | "modals": "မော်ဒယ်လ်များ"
11 | },
12 | "login": {
13 | "loginHere": "လော့ဂင်ဝင်ရန်",
14 | "username": "နာမည်",
15 | "enterUsername": "နာမည်ရိုက်ထည့်ပါ",
16 | "password": "စကားဝှက်",
17 | "enterPassword": "စကားဝှက်ရိုက်ထည့်ပါ",
18 | "login": "ဝင်မည်"
19 | },
20 | "form": {
21 | "pageTitle": "စိတ်ကြိုက်ပြင်ဆင်နိုင်ပြီး ပြန်လည်အသုံးပြုနိုင်တဲ့ Form Components",
22 | "pageDesc": "Dynamic ဖြစ်ပြီး အချိုးအစား ပြောင်းလဲနိုင်တဲ့ form တွေကို အလွယ်တကူ ဖန်တီးနိုင်စေဖို့၊ ပြန်လည်အသုံးပြုနိုင်တဲ့ component တွေကို မိမိစိတ်ကြိုက် ပြင်ဆင်နိုင်အောင် တိကျစွာ ဖော်ဆောင်ပေးပါတယ်။ လွယ်ကူတဲ့ validation နဲ့ အသုံးပြုသူအတွက် အသင့်တော်ဆုံး အဆင်ပြေအောင် accessibility ထည့်သွင်းပေးထားပြီး မည်သည့် project အတွက်မဆို လိုအပ်သလို စတိုင်အပြောင်းအလဲတွေ လွယ်လွယ်ကူကူ ပြုလုပ်နိုင်မှာ ဖြစ်ပါတယ်။"
23 | },
24 | "table": {
25 | "pageTitle": "စိတ်ကြိုက်ပြင်ဆင်နိုင်ပြီး ပြန်လည်အသုံးပြုနိုင်တဲ့ Table Components",
26 | "pageDesc": "Dynamic ဖြစ်ပြီး အချိုးအစားပြောင်းလဲနိုင်တဲ့ form တွေကို စိတ်ကြိုက်ပြင်ဆင်နိုင်တဲ့ ပြန်လည်အသုံးပြုနိုင်တဲ့ component တွေနဲ့ အလွယ်တကူ ဖန်တီးနိုင်ပါသည်။ ဘယ် project မဆို အဆင်ပြေစွာ develop လုပ်နိုင်ရန် built-in validation, accessibility, နဲ့ flexible styling ရွေးချယ်စရာတွေ ပါဝင်ထားပါတယ်။"
27 | },
28 | "modal": {
29 | "pageTitle": "စိတ်ကြိုက်ပြင်ဆင်နိုင်ပြီး ပြန်လည်အသုံးပြုနိုင်တဲ့ Modal Components",
30 | "pageDesc": "Dynamic ဖြစ်ပြီး အချိုးအစားပြောင်းလဲနိုင်တဲ့ form တွေကို စိတ်ကြိုက်ပြင်ဆင်နိုင်တဲ့ ပြန်လည်အသုံးပြုနိုင်တဲ့ component တွေနဲ့ အလွယ်တကူ ဖန်တီးနိုင်ပါတယ်။ မည်သည့် project မဆို ဖွံ့ဖြိုးရေးလုပ်ရန် built-in validation၊ အသုံးပြုသူအတွက် accessibility၊ နှင့် လွယ်ကူသော styling ရွေးချယ်မှုများဖြင့် လွယ်ကူစေပါသည်။"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinPyaeKyaw/shadcn-admin-starter-template/965735f31f0d52136bc1b4da672592de19175f38/src/components/.DS_Store
--------------------------------------------------------------------------------
/src/components/charts/chart-area-default.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { Area, AreaChart, CartesianGrid, XAxis } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A simple area chart";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 305 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 73 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function AreaChartDefault() {
38 | return (
39 |
40 |
41 | Area Chart
42 |
43 | Showing total visitors for the last 6 months
44 |
45 |
46 |
47 |
48 |
56 |
57 | value.slice(0, 3)}
63 | />
64 | }
67 | />
68 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | Trending up by 5.2% this month
83 |
84 |
85 | January - June 2024
86 |
87 |
88 |
89 |
90 |
91 | );
92 | }
93 |
--------------------------------------------------------------------------------
/src/components/charts/chart-area-linear.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { Area, AreaChart, CartesianGrid, XAxis } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A linear area chart";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 305 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 73 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function AreaChartLinear() {
38 | return (
39 |
40 |
41 | Area Chart - Linear
42 |
43 | Showing total visitors for the last 6 months
44 |
45 |
46 |
47 |
48 |
56 |
57 | value.slice(0, 3)}
63 | />
64 | }
67 | />
68 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | Trending up by 5.2% this month
83 |
84 |
85 | January - June 2024
86 |
87 |
88 |
89 |
90 |
91 | );
92 | }
93 |
--------------------------------------------------------------------------------
/src/components/charts/chart-area-step.tsx:
--------------------------------------------------------------------------------
1 | import { Activity, TrendingUp } from "lucide-react";
2 | import { Area, AreaChart, CartesianGrid, XAxis } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A step area chart";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 305 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 73 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | icon: Activity,
35 | },
36 | } satisfies ChartConfig;
37 |
38 | export default function AreaChartStep() {
39 | return (
40 |
41 |
42 | Area Chart - Step
43 |
44 | Showing total visitors for the last 6 months
45 |
46 |
47 |
48 |
49 |
57 |
58 | value.slice(0, 3)}
64 | />
65 | }
68 | />
69 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | Trending up by 5.2% this month
84 |
85 |
86 | January - June 2024
87 |
88 |
89 |
90 |
91 |
92 | );
93 | }
94 |
--------------------------------------------------------------------------------
/src/components/charts/chart-bar-default.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A bar chart";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 305 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 73 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function BarChartDefault() {
38 | return (
39 |
40 |
41 | Bar Chart
42 | January - June 2024
43 |
44 |
45 |
46 |
47 |
48 | value.slice(0, 3)}
54 | />
55 | }
58 | />
59 |
60 |
61 |
62 |
63 |
64 |
65 | Trending up by 5.2% this month
66 |
67 |
68 | Showing total visitors for the last 6 months
69 |
70 |
71 |
72 | );
73 | }
74 |
--------------------------------------------------------------------------------
/src/components/charts/chart-bar-horizontal.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { Bar, BarChart, XAxis, YAxis } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A horizontal bar chart";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 305 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 73 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function BarChartHorizontal() {
38 | return (
39 |
40 |
41 | Bar Chart - Horizontal
42 | January - June 2024
43 |
44 |
45 |
46 |
54 |
55 | value.slice(0, 3)}
62 | />
63 | }
66 | />
67 |
68 |
69 |
70 |
71 |
72 |
73 | Trending up by 5.2% this month
74 |
75 |
76 | Showing total visitors for the last 6 months
77 |
78 |
79 |
80 | );
81 | }
82 |
--------------------------------------------------------------------------------
/src/components/charts/chart-bar-label.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { Bar, BarChart, CartesianGrid, LabelList, XAxis } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A bar chart with a label";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 305 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 73 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function BarChartLabel() {
38 | return (
39 |
40 |
41 | Bar Chart - Label
42 | January - June 2024
43 |
44 |
45 |
46 |
53 |
54 | value.slice(0, 3)}
60 | />
61 | }
64 | />
65 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | Trending up by 5.2% this month
79 |
80 |
81 | Showing total visitors for the last 6 months
82 |
83 |
84 |
85 | );
86 | }
87 |
--------------------------------------------------------------------------------
/src/components/charts/chart-bar-multiple.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A multiple bar chart";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186, mobile: 80 },
23 | { month: "February", desktop: 305, mobile: 200 },
24 | { month: "March", desktop: 237, mobile: 120 },
25 | { month: "April", desktop: 73, mobile: 190 },
26 | { month: "May", desktop: 209, mobile: 130 },
27 | { month: "June", desktop: 214, mobile: 140 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | mobile: {
36 | label: "Mobile",
37 | color: "hsl(var(--chart-2))",
38 | },
39 | } satisfies ChartConfig;
40 |
41 | export default function BarChartMultiple() {
42 | return (
43 |
44 |
45 | Bar Chart - Multiple
46 | January - June 2024
47 |
48 |
49 |
50 |
51 |
52 | value.slice(0, 3)}
58 | />
59 | }
62 | />
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | Trending up by 5.2% this month
71 |
72 |
73 | Showing total visitors for the last 6 months
74 |
75 |
76 |
77 | );
78 | }
79 |
--------------------------------------------------------------------------------
/src/components/charts/chart-bar-negative.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { Bar, BarChart, CartesianGrid, Cell, LabelList } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A bar chart with negative values";
20 |
21 | const chartData = [
22 | { month: "January", visitors: 186 },
23 | { month: "February", visitors: 205 },
24 | { month: "March", visitors: -207 },
25 | { month: "April", visitors: 173 },
26 | { month: "May", visitors: -209 },
27 | { month: "June", visitors: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | visitors: {
32 | label: "Visitors",
33 | },
34 | } satisfies ChartConfig;
35 |
36 | export default function BarChartNegative() {
37 | return (
38 |
39 |
40 | Bar Chart - Negative
41 | January - June 2024
42 |
43 |
44 |
45 |
46 |
47 | }
50 | />
51 |
52 |
53 | {chartData.map((item) => (
54 | 0
58 | ? "hsl(var(--primary))"
59 | : "hsl(var(--chart-2))"
60 | }
61 | />
62 | ))}
63 | |
64 |
65 |
66 |
67 |
68 |
69 | Trending up by 5.2% this month
70 |
71 |
72 | Showing total visitors for the last 6 months
73 |
74 |
75 |
76 | );
77 | }
78 |
--------------------------------------------------------------------------------
/src/components/charts/chart-bar-stacked.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartLegend,
16 | ChartLegendContent,
17 | ChartTooltip,
18 | ChartTooltipContent,
19 | } from "@components/ui/chart";
20 |
21 | export const description = "A stacked bar chart with a legend";
22 |
23 | const chartData = [
24 | { month: "January", desktop: 186, mobile: 80 },
25 | { month: "February", desktop: 305, mobile: 200 },
26 | { month: "March", desktop: 237, mobile: 120 },
27 | { month: "April", desktop: 73, mobile: 190 },
28 | { month: "May", desktop: 209, mobile: 130 },
29 | { month: "June", desktop: 214, mobile: 140 },
30 | ];
31 |
32 | const chartConfig = {
33 | desktop: {
34 | label: "Desktop",
35 | color: "hsl(var(--primary))",
36 | },
37 | mobile: {
38 | label: "Mobile",
39 | color: "hsl(var(--chart-2))",
40 | },
41 | } satisfies ChartConfig;
42 |
43 | export default function BarChartStacked() {
44 | return (
45 |
46 |
47 | Bar Chart - Stacked + Legend
48 | January - June 2024
49 |
50 |
51 |
52 |
53 |
54 | value.slice(0, 3)}
60 | />
61 | } />
62 | } />
63 |
69 |
75 |
76 |
77 |
78 |
79 |
80 | Trending up by 5.2% this month
81 |
82 |
83 | Showing total visitors for the last 6 months
84 |
85 |
86 |
87 | );
88 | }
89 |
--------------------------------------------------------------------------------
/src/components/charts/chart-line-default.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { CartesianGrid, Line, LineChart, XAxis } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A line chart";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 305 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 73 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function LineChartDefault() {
38 | return (
39 |
40 |
41 | Line Chart
42 | January - June 2024
43 |
44 |
45 |
46 |
54 |
55 | value.slice(0, 3)}
61 | />
62 | }
65 | />
66 |
73 |
74 |
75 |
76 |
77 |
78 | Trending up by 5.2% this month
79 |
80 |
81 | Showing total visitors for the last 6 months
82 |
83 |
84 |
85 | );
86 | }
87 |
--------------------------------------------------------------------------------
/src/components/charts/chart-line-linear.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { CartesianGrid, Line, LineChart, XAxis } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A linear line chart";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 305 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 73 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function LineChartLinear() {
38 | return (
39 |
40 |
41 | Line Chart - Linear
42 | January - June 2024
43 |
44 |
45 |
46 |
54 |
55 | value.slice(0, 3)}
61 | />
62 | }
65 | />
66 |
73 |
74 |
75 |
76 |
77 |
78 | Trending up by 5.2% this month
79 |
80 |
81 | Showing total visitors for the last 6 months
82 |
83 |
84 |
85 | );
86 | }
87 |
--------------------------------------------------------------------------------
/src/components/charts/chart-line-step.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { CartesianGrid, Line, LineChart, XAxis } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A line chart with step";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 305 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 73 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function LineChartStep() {
38 | return (
39 |
40 |
41 | Line Chart - Step
42 | January - June 2024
43 |
44 |
45 |
46 |
54 |
55 | value.slice(0, 3)}
61 | />
62 | }
65 | />
66 |
73 |
74 |
75 |
76 |
77 |
78 | Trending up by 5.2% this month
79 |
80 |
81 | Showing total visitors for the last 6 months
82 |
83 |
84 |
85 | );
86 | }
87 |
--------------------------------------------------------------------------------
/src/components/charts/chart-pie-donut.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { Pie, PieChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A donut chart";
20 |
21 | const chartData = [
22 | { browser: "chrome", visitors: 275, fill: "var(--color-chrome)" },
23 | { browser: "safari", visitors: 200, fill: "var(--color-safari)" },
24 | { browser: "firefox", visitors: 187, fill: "var(--color-firefox)" },
25 | { browser: "edge", visitors: 173, fill: "var(--color-edge)" },
26 | { browser: "other", visitors: 90, fill: "var(--color-other)" },
27 | ];
28 |
29 | const chartConfig = {
30 | visitors: {
31 | label: "Visitors",
32 | },
33 | chrome: {
34 | label: "Chrome",
35 | color: "hsl(var(--primary))",
36 | },
37 | safari: {
38 | label: "Safari",
39 | color: "hsl(var(--chart-2))",
40 | },
41 | firefox: {
42 | label: "Firefox",
43 | color: "hsl(var(--chart-3))",
44 | },
45 | edge: {
46 | label: "Edge",
47 | color: "hsl(var(--chart-4))",
48 | },
49 | other: {
50 | label: "Other",
51 | color: "hsl(var(--chart-5))",
52 | },
53 | } satisfies ChartConfig;
54 |
55 | export default function PieChartDonut() {
56 | return (
57 |
58 |
59 | Pie Chart - Donut
60 | January - June 2024
61 |
62 |
63 |
67 |
68 | }
71 | />
72 |
78 |
79 |
80 |
81 |
82 |
83 | Trending up by 5.2% this month
84 |
85 |
86 | Showing total visitors for the last 6 months
87 |
88 |
89 |
90 | );
91 | }
92 |
--------------------------------------------------------------------------------
/src/components/charts/chart-pie-label.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { Pie, PieChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A pie chart with a label";
20 |
21 | const chartData = [
22 | { browser: "chrome", visitors: 275, fill: "var(--color-chrome)" },
23 | { browser: "safari", visitors: 200, fill: "var(--color-safari)" },
24 | { browser: "firefox", visitors: 187, fill: "var(--color-firefox)" },
25 | { browser: "edge", visitors: 173, fill: "var(--color-edge)" },
26 | { browser: "other", visitors: 90, fill: "var(--color-other)" },
27 | ];
28 |
29 | const chartConfig = {
30 | visitors: {
31 | label: "Visitors",
32 | },
33 | chrome: {
34 | label: "Chrome",
35 | color: "hsl(var(--primary))",
36 | },
37 | safari: {
38 | label: "Safari",
39 | color: "hsl(var(--chart-2))",
40 | },
41 | firefox: {
42 | label: "Firefox",
43 | color: "hsl(var(--chart-3))",
44 | },
45 | edge: {
46 | label: "Edge",
47 | color: "hsl(var(--chart-4))",
48 | },
49 | other: {
50 | label: "Other",
51 | color: "hsl(var(--chart-5))",
52 | },
53 | } satisfies ChartConfig;
54 |
55 | export default function PieChartLabel() {
56 | return (
57 |
58 |
59 | Pie Chart - Label
60 | January - June 2024
61 |
62 |
63 |
67 |
68 | } />
69 |
70 |
71 |
72 |
73 |
74 |
75 | Trending up by 5.2% this month
76 |
77 |
78 | Showing total visitors for the last 6 months
79 |
80 |
81 |
82 | );
83 | }
84 |
--------------------------------------------------------------------------------
/src/components/charts/chart-pie-legend.tsx:
--------------------------------------------------------------------------------
1 | import { Pie, PieChart } from "recharts";
2 |
3 | import {
4 | Card,
5 | CardContent,
6 | CardDescription,
7 | CardHeader,
8 | CardTitle,
9 | } from "@components/ui/card";
10 | import {
11 | ChartConfig,
12 | ChartContainer,
13 | ChartLegend,
14 | ChartLegendContent,
15 | } from "@components/ui/chart";
16 |
17 | export const description = "A pie chart with a legend";
18 |
19 | const chartData = [
20 | { browser: "chrome", visitors: 275, fill: "var(--color-chrome)" },
21 | { browser: "safari", visitors: 200, fill: "var(--color-safari)" },
22 | { browser: "firefox", visitors: 187, fill: "var(--color-firefox)" },
23 | { browser: "edge", visitors: 173, fill: "var(--color-edge)" },
24 | { browser: "other", visitors: 90, fill: "var(--color-other)" },
25 | ];
26 |
27 | const chartConfig = {
28 | visitors: {
29 | label: "Visitors",
30 | },
31 | chrome: {
32 | label: "Chrome",
33 | color: "hsl(var(--primary))",
34 | },
35 | safari: {
36 | label: "Safari",
37 | color: "hsl(var(--chart-2))",
38 | },
39 | firefox: {
40 | label: "Firefox",
41 | color: "hsl(var(--chart-3))",
42 | },
43 | edge: {
44 | label: "Edge",
45 | color: "hsl(var(--chart-4))",
46 | },
47 | other: {
48 | label: "Other",
49 | color: "hsl(var(--chart-5))",
50 | },
51 | } satisfies ChartConfig;
52 |
53 | export default function PieChartLegend() {
54 | return (
55 |
56 |
57 | Pie Chart - Legend
58 | January - June 2024
59 |
60 |
61 |
65 |
66 |
67 | }
69 | className="-translate-y-2 flex-wrap gap-2 [&>*]:basis-1/4 [&>*]:justify-center"
70 | />
71 |
72 |
73 |
74 |
75 | );
76 | }
77 |
--------------------------------------------------------------------------------
/src/components/charts/chart-pie-separator-none.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { Pie, PieChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A pie chart with no separator";
20 |
21 | const chartData = [
22 | { browser: "chrome", visitors: 275, fill: "var(--color-chrome)" },
23 | { browser: "safari", visitors: 200, fill: "var(--color-safari)" },
24 | { browser: "firefox", visitors: 187, fill: "var(--color-firefox)" },
25 | { browser: "edge", visitors: 173, fill: "var(--color-edge)" },
26 | { browser: "other", visitors: 90, fill: "var(--color-other)" },
27 | ];
28 |
29 | const chartConfig = {
30 | visitors: {
31 | label: "Visitors",
32 | },
33 | chrome: {
34 | label: "Chrome",
35 | color: "hsl(var(--primary))",
36 | },
37 | safari: {
38 | label: "Safari",
39 | color: "hsl(var(--chart-2))",
40 | },
41 | firefox: {
42 | label: "Firefox",
43 | color: "hsl(var(--chart-3))",
44 | },
45 | edge: {
46 | label: "Edge",
47 | color: "hsl(var(--chart-4))",
48 | },
49 | other: {
50 | label: "Other",
51 | color: "hsl(var(--chart-5))",
52 | },
53 | } satisfies ChartConfig;
54 |
55 | export default function PieChartSeparatorNone() {
56 | return (
57 |
58 |
59 | Pie Chart - Separator None
60 | January - June 2024
61 |
62 |
63 |
67 |
68 | }
71 | />
72 |
78 |
79 |
80 |
81 |
82 |
83 | Trending up by 5.2% this month
84 |
85 |
86 | Showing total visitors for the last 6 months
87 |
88 |
89 |
90 | );
91 | }
92 |
--------------------------------------------------------------------------------
/src/components/charts/chart-pie-simple.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { Pie, PieChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A simple pie chart";
20 |
21 | const chartData = [
22 | { browser: "chrome", visitors: 275, fill: "var(--color-chrome)" },
23 | { browser: "safari", visitors: 200, fill: "var(--color-safari)" },
24 | { browser: "firefox", visitors: 187, fill: "var(--color-firefox)" },
25 | { browser: "edge", visitors: 173, fill: "var(--color-edge)" },
26 | { browser: "other", visitors: 90, fill: "var(--color-other)" },
27 | ];
28 |
29 | const chartConfig = {
30 | visitors: {
31 | label: "Visitors",
32 | },
33 | chrome: {
34 | label: "Chrome",
35 | color: "hsl(var(--primary))",
36 | },
37 | safari: {
38 | label: "Safari",
39 | color: "hsl(var(--chart-2))",
40 | },
41 | firefox: {
42 | label: "Firefox",
43 | color: "hsl(var(--chart-3))",
44 | },
45 | edge: {
46 | label: "Edge",
47 | color: "hsl(var(--chart-4))",
48 | },
49 | other: {
50 | label: "Other",
51 | color: "hsl(var(--chart-5))",
52 | },
53 | } satisfies ChartConfig;
54 |
55 | export default function PieChartSimple() {
56 | return (
57 |
58 |
59 | Pie Chart
60 | January - June 2024
61 |
62 |
63 |
67 |
68 | }
71 | />
72 |
73 |
74 |
75 |
76 |
77 |
78 | Trending up by 5.2% this month
79 |
80 |
81 | Showing total visitors for the last 6 months
82 |
83 |
84 |
85 | );
86 | }
87 |
--------------------------------------------------------------------------------
/src/components/charts/chart-radar-default.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A radar chart";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 305 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 273 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function RadarChartDefault() {
38 | return (
39 |
40 |
41 | Radar Chart
42 |
43 | Showing total visitors for the last 6 months
44 |
45 |
46 |
47 |
51 |
52 | } />
53 |
54 |
55 |
60 |
61 |
62 |
63 |
64 |
65 | Trending up by 5.2% this month
66 |
67 |
68 | January - June 2024
69 |
70 |
71 |
72 | );
73 | }
74 |
--------------------------------------------------------------------------------
/src/components/charts/chart-radar-dots.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A radar chart with dots";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 305 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 273 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function RadarChartDots() {
38 | return (
39 |
40 |
41 | Radar Chart - Dots
42 |
43 | Showing total visitors for the last 6 months
44 |
45 |
46 |
47 |
51 |
52 | } />
53 |
54 |
55 |
64 |
65 |
66 |
67 |
68 |
69 | Trending up by 5.2% this month
70 |
71 |
72 | January - June 2024
73 |
74 |
75 |
76 | );
77 | }
78 |
--------------------------------------------------------------------------------
/src/components/charts/chart-radar-grid-circle-fill.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A radar chart with a grid and circle fill";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 285 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 203 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 264 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function RadarChartGridCircleFill() {
38 | return (
39 |
40 |
41 | Radar Chart - Grid Circle Filled
42 |
43 | Showing total visitors for the last 6 months
44 |
45 |
46 |
47 |
51 |
52 | } />
53 |
57 |
58 |
63 |
64 |
65 |
66 |
67 |
68 | Trending up by 5.2% this month
69 |
70 |
71 | January - June 2024
72 |
73 |
74 |
75 | );
76 | }
77 |
--------------------------------------------------------------------------------
/src/components/charts/chart-radar-grid-circle-no-lines.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A radar chart with a grid and circle fill";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 305 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 203 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function RadarChartGridCircleNoLines() {
38 | return (
39 |
40 |
41 | Radar Chart - Grid Circle - No lines
42 |
43 | Showing total visitors for the last 6 months
44 |
45 |
46 |
47 |
51 |
52 | }
55 | />
56 |
57 |
58 |
67 |
68 |
69 |
70 |
71 |
72 | Trending up by 5.2% this month
73 |
74 |
75 | January - June 2024
76 |
77 |
78 |
79 | );
80 | }
81 |
--------------------------------------------------------------------------------
/src/components/charts/chart-radar-grid-circle.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A radar chart with a grid and circle";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 305 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 273 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function RadarChartGridCircle() {
38 | return (
39 |
40 |
41 | Radar Chart - Grid Circle
42 |
43 | Showing total visitors for the last 6 months
44 |
45 |
46 |
47 |
51 |
52 | }
55 | />
56 |
57 |
58 |
67 |
68 |
69 |
70 |
71 |
72 | Trending up by 5.2% this month
73 |
74 |
75 | January - June 2024
76 |
77 |
78 |
79 | );
80 | }
81 |
--------------------------------------------------------------------------------
/src/components/charts/chart-radar-grid-custom.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A radar chart with a custom grid";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 305 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 273 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function RadarChartGridCustom() {
38 | return (
39 |
40 |
41 | Radar Chart - Grid Custom
42 |
43 | Showing total visitors for the last 6 months
44 |
45 |
46 |
47 |
51 |
52 | }
55 | />
56 |
57 |
58 |
63 |
64 |
65 |
66 |
67 |
68 | Trending up by 5.2% this month
69 |
70 |
71 | January - June 2024
72 |
73 |
74 |
75 | );
76 | }
77 |
--------------------------------------------------------------------------------
/src/components/charts/chart-radar-grid-fill.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A radar chart with a grid filled";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 285 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 203 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 264 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function RadarChartGridFill() {
38 | return (
39 |
40 |
41 | Radar Chart - Grid Filled
42 |
43 | Showing total visitors for the last 6 months
44 |
45 |
46 |
47 |
51 |
52 | }
55 | />
56 |
57 |
58 |
63 |
64 |
65 |
66 |
67 |
68 | Trending up by 5.2% this month
69 |
70 |
71 | January - June 2024
72 |
73 |
74 |
75 | );
76 | }
77 |
--------------------------------------------------------------------------------
/src/components/charts/chart-radar-grid-none.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { PolarAngleAxis, Radar, RadarChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A radar chart with no grid";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186 },
23 | { month: "February", desktop: 305 },
24 | { month: "March", desktop: 237 },
25 | { month: "April", desktop: 273 },
26 | { month: "May", desktop: 209 },
27 | { month: "June", desktop: 214 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | } satisfies ChartConfig;
36 |
37 | export default function RadarChartGridNone() {
38 | return (
39 |
40 |
41 | Radar Chart - Grid None
42 |
43 | Showing total visitors for the last 6 months
44 |
45 |
46 |
47 |
51 |
52 | }
55 | />
56 |
57 |
66 |
67 |
68 |
69 |
70 |
71 | Trending up by 5.2% this month
72 |
73 |
74 | January - June 2024
75 |
76 |
77 |
78 | );
79 | }
80 |
--------------------------------------------------------------------------------
/src/components/charts/chart-radar-legend.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartLegend,
16 | ChartLegendContent,
17 | ChartTooltip,
18 | ChartTooltipContent,
19 | } from "@components/ui/chart";
20 |
21 | export const description = "A radar chart with a legend";
22 |
23 | const chartData = [
24 | { month: "January", desktop: 186, mobile: 80 },
25 | { month: "February", desktop: 305, mobile: 200 },
26 | { month: "March", desktop: 237, mobile: 120 },
27 | { month: "April", desktop: 73, mobile: 190 },
28 | { month: "May", desktop: 209, mobile: 130 },
29 | { month: "June", desktop: 214, mobile: 140 },
30 | ];
31 |
32 | const chartConfig = {
33 | desktop: {
34 | label: "Desktop",
35 | color: "hsl(var(--primary))",
36 | },
37 | mobile: {
38 | label: "Mobile",
39 | color: "hsl(var(--chart-2))",
40 | },
41 | } satisfies ChartConfig;
42 |
43 | export default function RadarChartLegend() {
44 | return (
45 |
46 |
47 | Radar Chart - Legend
48 |
49 | Showing total visitors for the last 6 months
50 |
51 |
52 |
53 |
57 |
64 | }
67 | />
68 |
69 |
70 |
75 |
76 | } />
77 |
78 |
79 |
80 |
81 |
82 | Trending up by 5.2% this month
83 |
84 |
85 | January - June 2024
86 |
87 |
88 |
89 | );
90 | }
91 |
--------------------------------------------------------------------------------
/src/components/charts/chart-radar-multiple.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { PolarAngleAxis, PolarGrid, Radar, RadarChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A radar chart with multiple data";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186, mobile: 80 },
23 | { month: "February", desktop: 305, mobile: 200 },
24 | { month: "March", desktop: 237, mobile: 120 },
25 | { month: "April", desktop: 73, mobile: 190 },
26 | { month: "May", desktop: 209, mobile: 130 },
27 | { month: "June", desktop: 214, mobile: 140 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | mobile: {
36 | label: "Mobile",
37 | color: "hsl(var(--chart-2))",
38 | },
39 | } satisfies ChartConfig;
40 |
41 | export default function RadarChartMultiple() {
42 | return (
43 |
44 |
45 | Radar Chart - Multiple
46 |
47 | Showing total visitors for the last 6 months
48 |
49 |
50 |
51 |
55 |
56 | }
59 | />
60 |
61 |
62 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | Trending up by 5.2% this month
74 |
75 |
76 | January - June 2024
77 |
78 |
79 |
80 | );
81 | }
82 |
--------------------------------------------------------------------------------
/src/components/charts/chart-radar-radius.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { PolarGrid, PolarRadiusAxis, Radar, RadarChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A radar chart with a radius axis";
20 |
21 | const chartData = [
22 | { month: "January", desktop: 186, mobile: 80 },
23 | { month: "February", desktop: 305, mobile: 200 },
24 | { month: "March", desktop: 237, mobile: 120 },
25 | { month: "April", desktop: 73, mobile: 190 },
26 | { month: "May", desktop: 209, mobile: 130 },
27 | { month: "June", desktop: 214, mobile: 140 },
28 | ];
29 |
30 | const chartConfig = {
31 | desktop: {
32 | label: "Desktop",
33 | color: "hsl(var(--primary))",
34 | },
35 | mobile: {
36 | label: "Mobile",
37 | color: "hsl(var(--chart-2))",
38 | },
39 | } satisfies ChartConfig;
40 |
41 | export default function RadarChartRadius() {
42 | return (
43 |
44 |
45 | Radar Chart - Radius Axis
46 |
47 | Showing total visitors for the last 6 months
48 |
49 |
50 |
51 |
55 |
56 |
60 | }
61 | />
62 |
63 |
68 |
69 |
75 |
76 |
77 |
78 |
79 |
80 | Trending up by 5.2% this month
81 |
82 |
83 | January - June 2024
84 |
85 |
86 |
87 | );
88 | }
89 |
--------------------------------------------------------------------------------
/src/components/charts/chart-radial-grid.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { PolarGrid, RadialBar, RadialBarChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A radial chart with a grid";
20 |
21 | const chartData = [
22 | { browser: "chrome", visitors: 275, fill: "var(--color-chrome)" },
23 | { browser: "safari", visitors: 200, fill: "var(--color-safari)" },
24 | { browser: "firefox", visitors: 187, fill: "var(--color-firefox)" },
25 | { browser: "edge", visitors: 173, fill: "var(--color-edge)" },
26 | { browser: "other", visitors: 90, fill: "var(--color-other)" },
27 | ];
28 |
29 | const chartConfig = {
30 | visitors: {
31 | label: "Visitors",
32 | },
33 | chrome: {
34 | label: "Chrome",
35 | color: "hsl(var(--primary))",
36 | },
37 | safari: {
38 | label: "Safari",
39 | color: "hsl(var(--chart-2))",
40 | },
41 | firefox: {
42 | label: "Firefox",
43 | color: "hsl(var(--chart-3))",
44 | },
45 | edge: {
46 | label: "Edge",
47 | color: "hsl(var(--chart-4))",
48 | },
49 | other: {
50 | label: "Other",
51 | color: "hsl(var(--chart-5))",
52 | },
53 | } satisfies ChartConfig;
54 |
55 | export default function RadialChartGrid() {
56 | return (
57 |
58 |
59 | Radial Chart - Grid
60 | January - June 2024
61 |
62 |
63 |
67 |
68 | }
71 | />
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | Trending up by 5.2% this month
80 |
81 |
82 | Showing total visitors for the last 6 months
83 |
84 |
85 |
86 | );
87 | }
88 |
--------------------------------------------------------------------------------
/src/components/charts/chart-radial-simple.tsx:
--------------------------------------------------------------------------------
1 | import { TrendingUp } from "lucide-react";
2 | import { RadialBar, RadialBarChart } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardFooter,
9 | CardHeader,
10 | CardTitle,
11 | } from "@components/ui/card";
12 | import {
13 | ChartConfig,
14 | ChartContainer,
15 | ChartTooltip,
16 | ChartTooltipContent,
17 | } from "@components/ui/chart";
18 |
19 | export const description = "A radial chart";
20 |
21 | const chartData = [
22 | { browser: "chrome", visitors: 275, fill: "var(--color-chrome)" },
23 | { browser: "safari", visitors: 200, fill: "var(--color-safari)" },
24 | { browser: "firefox", visitors: 187, fill: "var(--color-firefox)" },
25 | { browser: "edge", visitors: 173, fill: "var(--color-edge)" },
26 | { browser: "other", visitors: 90, fill: "var(--color-other)" },
27 | ];
28 |
29 | const chartConfig = {
30 | visitors: {
31 | label: "Visitors",
32 | },
33 | chrome: {
34 | label: "Chrome",
35 | color: "hsl(var(--primary))",
36 | },
37 | safari: {
38 | label: "Safari",
39 | color: "hsl(var(--chart-2))",
40 | },
41 | firefox: {
42 | label: "Firefox",
43 | color: "hsl(var(--chart-3))",
44 | },
45 | edge: {
46 | label: "Edge",
47 | color: "hsl(var(--chart-4))",
48 | },
49 | other: {
50 | label: "Other",
51 | color: "hsl(var(--chart-5))",
52 | },
53 | } satisfies ChartConfig;
54 |
55 | export default function RadialChartSimple() {
56 | return (
57 |
58 |
59 | Radial Chart
60 | January - June 2024
61 |
62 |
63 |
67 |
68 | }
71 | />
72 |
73 |
74 |
75 |
76 |
77 |
78 | Trending up by 5.2% this month
79 |
80 |
81 | Showing total visitors for the last 6 months
82 |
83 |
84 |
85 | );
86 | }
87 |
--------------------------------------------------------------------------------
/src/components/charts/chart-tooltip-default.tsx:
--------------------------------------------------------------------------------
1 | import { Bar, BarChart, XAxis } from "recharts";
2 |
3 | import {
4 | Card,
5 | CardContent,
6 | CardDescription,
7 | CardHeader,
8 | CardTitle,
9 | } from "@components/ui/card";
10 | import {
11 | ChartConfig,
12 | ChartContainer,
13 | ChartTooltip,
14 | ChartTooltipContent,
15 | } from "@components/ui/chart";
16 |
17 | export const description = "A stacked bar chart with a legend";
18 |
19 | const chartData = [
20 | { date: "2024-07-15", running: 450, swimming: 300 },
21 | { date: "2024-07-16", running: 380, swimming: 420 },
22 | { date: "2024-07-17", running: 520, swimming: 120 },
23 | { date: "2024-07-18", running: 140, swimming: 550 },
24 | { date: "2024-07-19", running: 600, swimming: 350 },
25 | { date: "2024-07-20", running: 480, swimming: 400 },
26 | ];
27 |
28 | const chartConfig = {
29 | running: {
30 | label: "Running",
31 | color: "hsl(var(--primary))",
32 | },
33 | swimming: {
34 | label: "Swimming",
35 | color: "hsl(var(--chart-2))",
36 | },
37 | } satisfies ChartConfig;
38 |
39 | export default function TooltipChartDefault() {
40 | return (
41 |
42 |
43 | Tooltip - Default
44 |
45 | Default tooltip with ChartTooltipContent.
46 |
47 |
48 |
49 |
50 |
51 | {
57 | return new Date(value).toLocaleDateString("en-US", {
58 | weekday: "short",
59 | });
60 | }}
61 | />
62 |
68 |
74 | }
76 | cursor={false}
77 | defaultIndex={1}
78 | />
79 |
80 |
81 |
82 |
83 | );
84 | }
85 |
--------------------------------------------------------------------------------
/src/components/charts/chart-tooltip-icons.tsx:
--------------------------------------------------------------------------------
1 | import { Footprints, Waves } from "lucide-react";
2 | import { Bar, BarChart, XAxis } from "recharts";
3 |
4 | import {
5 | Card,
6 | CardContent,
7 | CardDescription,
8 | CardHeader,
9 | CardTitle,
10 | } from "@components/ui/card";
11 | import {
12 | ChartConfig,
13 | ChartContainer,
14 | ChartTooltip,
15 | ChartTooltipContent,
16 | } from "@components/ui/chart";
17 |
18 | export const description = "A stacked bar chart with a legend";
19 |
20 | const chartData = [
21 | { date: "2024-07-15", running: 450, swimming: 300 },
22 | { date: "2024-07-16", running: 380, swimming: 420 },
23 | { date: "2024-07-17", running: 520, swimming: 120 },
24 | { date: "2024-07-18", running: 140, swimming: 550 },
25 | { date: "2024-07-19", running: 600, swimming: 350 },
26 | { date: "2024-07-20", running: 480, swimming: 400 },
27 | ];
28 |
29 | const chartConfig = {
30 | running: {
31 | label: "Running",
32 | color: "hsl(var(--primary))",
33 | icon: Footprints,
34 | },
35 | swimming: {
36 | label: "Swimming",
37 | color: "hsl(var(--chart-2))",
38 | icon: Waves,
39 | },
40 | } satisfies ChartConfig;
41 |
42 | export default function TooltipChartIcon() {
43 | return (
44 |
45 |
46 | Tooltip - Icons
47 | Tooltip with icons.
48 |
49 |
50 |
51 |
52 | {
58 | return new Date(value).toLocaleDateString("en-US", {
59 | weekday: "short",
60 | });
61 | }}
62 | />
63 |
69 |
75 | }
77 | cursor={false}
78 | defaultIndex={1}
79 | />
80 |
81 |
82 |
83 |
84 | );
85 | }
86 |
--------------------------------------------------------------------------------
/src/components/charts/chart-tooltip-indicator-line.tsx:
--------------------------------------------------------------------------------
1 | import { Bar, BarChart, XAxis } from "recharts";
2 |
3 | import {
4 | Card,
5 | CardContent,
6 | CardDescription,
7 | CardHeader,
8 | CardTitle,
9 | } from "@components/ui/card";
10 | import {
11 | ChartConfig,
12 | ChartContainer,
13 | ChartTooltip,
14 | ChartTooltipContent,
15 | } from "@components/ui/chart";
16 |
17 | export const description = "A stacked bar chart with a legend";
18 |
19 | const chartData = [
20 | { date: "2024-07-15", running: 450, swimming: 300 },
21 | { date: "2024-07-16", running: 380, swimming: 420 },
22 | { date: "2024-07-17", running: 520, swimming: 120 },
23 | { date: "2024-07-18", running: 140, swimming: 550 },
24 | { date: "2024-07-19", running: 600, swimming: 350 },
25 | { date: "2024-07-20", running: 480, swimming: 400 },
26 | ];
27 |
28 | const chartConfig = {
29 | running: {
30 | label: "Running",
31 | color: "hsl(var(--primary))",
32 | },
33 | swimming: {
34 | label: "Swimming",
35 | color: "hsl(var(--chart-2))",
36 | },
37 | } satisfies ChartConfig;
38 |
39 | export default function TooltipChartIndicatorLine() {
40 | return (
41 |
42 |
43 | Tooltip - Line Indicator
44 | Tooltip with line indicator.
45 |
46 |
47 |
48 |
49 | {
55 | return new Date(value).toLocaleDateString("en-US", {
56 | weekday: "short",
57 | });
58 | }}
59 | />
60 |
66 |
72 | }
74 | cursor={false}
75 | defaultIndex={1}
76 | />
77 |
78 |
79 |
80 |
81 | );
82 | }
83 |
--------------------------------------------------------------------------------
/src/components/charts/chart-tooltip-indicator-none.tsx:
--------------------------------------------------------------------------------
1 | import { Bar, BarChart, XAxis } from "recharts";
2 |
3 | import {
4 | Card,
5 | CardContent,
6 | CardDescription,
7 | CardHeader,
8 | CardTitle,
9 | } from "@components/ui/card";
10 | import {
11 | ChartConfig,
12 | ChartContainer,
13 | ChartTooltip,
14 | ChartTooltipContent,
15 | } from "@components/ui/chart";
16 |
17 | export const description = "A stacked bar chart with a legend";
18 |
19 | const chartData = [
20 | { date: "2024-07-15", running: 450, swimming: 300 },
21 | { date: "2024-07-16", running: 380, swimming: 420 },
22 | { date: "2024-07-17", running: 520, swimming: 120 },
23 | { date: "2024-07-18", running: 140, swimming: 550 },
24 | { date: "2024-07-19", running: 600, swimming: 350 },
25 | { date: "2024-07-20", running: 480, swimming: 400 },
26 | ];
27 |
28 | const chartConfig = {
29 | running: {
30 | label: "Running",
31 | color: "hsl(var(--primary))",
32 | },
33 | swimming: {
34 | label: "Swimming",
35 | color: "hsl(var(--chart-2))",
36 | },
37 | } satisfies ChartConfig;
38 |
39 | export default function TooltipChartIndicatorNone() {
40 | return (
41 |
42 |
43 | Tooltip - No Indicator
44 | Tooltip with no indicator.
45 |
46 |
47 |
48 |
49 | {
55 | return new Date(value).toLocaleDateString("en-US", {
56 | weekday: "short",
57 | });
58 | }}
59 | />
60 |
66 |
72 | }
74 | cursor={false}
75 | defaultIndex={1}
76 | />
77 |
78 |
79 |
80 |
81 | );
82 | }
83 |
--------------------------------------------------------------------------------
/src/components/charts/chart-tooltip-label-custom.tsx:
--------------------------------------------------------------------------------
1 | import { Bar, BarChart, XAxis } from "recharts";
2 |
3 | import {
4 | Card,
5 | CardContent,
6 | CardDescription,
7 | CardHeader,
8 | CardTitle,
9 | } from "@components/ui/card";
10 | import {
11 | ChartConfig,
12 | ChartContainer,
13 | ChartTooltip,
14 | ChartTooltipContent,
15 | } from "@components/ui/chart";
16 |
17 | export const description = "A stacked bar chart with a legend";
18 |
19 | const chartData = [
20 | { date: "2024-07-15", running: 450, swimming: 300 },
21 | { date: "2024-07-16", running: 380, swimming: 420 },
22 | { date: "2024-07-17", running: 520, swimming: 120 },
23 | { date: "2024-07-18", running: 140, swimming: 550 },
24 | { date: "2024-07-19", running: 600, swimming: 350 },
25 | { date: "2024-07-20", running: 480, swimming: 400 },
26 | ];
27 |
28 | const chartConfig = {
29 | activities: {
30 | label: "Activities",
31 | },
32 | running: {
33 | label: "Running",
34 | color: "hsl(var(--primary))",
35 | },
36 | swimming: {
37 | label: "Swimming",
38 | color: "hsl(var(--chart-2))",
39 | },
40 | } satisfies ChartConfig;
41 |
42 | export default function TooltipChartLabelCustom() {
43 | return (
44 |
45 |
46 | Tooltip - Custom label
47 |
48 | Tooltip with custom label from chartConfig.
49 |
50 |
51 |
52 |
53 |
54 | {
60 | return new Date(value).toLocaleDateString("en-US", {
61 | weekday: "short",
62 | });
63 | }}
64 | />
65 |
71 |
77 |
80 | }
81 | cursor={false}
82 | defaultIndex={1}
83 | />
84 |
85 |
86 |
87 |
88 | );
89 | }
90 |
--------------------------------------------------------------------------------
/src/components/charts/chart-tooltip-label-formatter.tsx:
--------------------------------------------------------------------------------
1 | import { Bar, BarChart, XAxis } from "recharts";
2 |
3 | import {
4 | Card,
5 | CardContent,
6 | CardDescription,
7 | CardHeader,
8 | CardTitle,
9 | } from "@components/ui/card";
10 | import {
11 | ChartConfig,
12 | ChartContainer,
13 | ChartTooltip,
14 | ChartTooltipContent,
15 | } from "@components/ui/chart";
16 |
17 | export const description = "A stacked bar chart with a legend";
18 |
19 | const chartData = [
20 | { date: "2024-07-15", running: 450, swimming: 300 },
21 | { date: "2024-07-16", running: 380, swimming: 420 },
22 | { date: "2024-07-17", running: 520, swimming: 120 },
23 | { date: "2024-07-18", running: 140, swimming: 550 },
24 | { date: "2024-07-19", running: 600, swimming: 350 },
25 | { date: "2024-07-20", running: 480, swimming: 400 },
26 | ];
27 |
28 | const chartConfig = {
29 | running: {
30 | label: "Running",
31 | color: "hsl(var(--primary))",
32 | },
33 | swimming: {
34 | label: "Swimming",
35 | color: "hsl(var(--chart-2))",
36 | },
37 | } satisfies ChartConfig;
38 |
39 | export default function TooltipChartLabelFormatter() {
40 | return (
41 |
42 |
43 | Tooltip - Label Formatter
44 | Tooltip with label formatter.
45 |
46 |
47 |
48 |
49 | {
55 | return new Date(value).toLocaleDateString("en-US", {
56 | weekday: "short",
57 | });
58 | }}
59 | />
60 |
66 |
72 | {
76 | return new Date(value).toLocaleDateString("en-US", {
77 | day: "numeric",
78 | month: "long",
79 | year: "numeric",
80 | });
81 | }}
82 | />
83 | }
84 | cursor={false}
85 | defaultIndex={1}
86 | />
87 |
88 |
89 |
90 |
91 | );
92 | }
93 |
--------------------------------------------------------------------------------
/src/components/charts/chart-tooltip-label-none.tsx:
--------------------------------------------------------------------------------
1 | import { Bar, BarChart, XAxis } from "recharts";
2 |
3 | import {
4 | Card,
5 | CardContent,
6 | CardDescription,
7 | CardHeader,
8 | CardTitle,
9 | } from "@components/ui/card";
10 | import {
11 | ChartConfig,
12 | ChartContainer,
13 | ChartTooltip,
14 | ChartTooltipContent,
15 | } from "@components/ui/chart";
16 |
17 | export const description = "A stacked bar chart with a legend";
18 |
19 | const chartData = [
20 | { date: "2024-07-15", running: 450, swimming: 300 },
21 | { date: "2024-07-16", running: 380, swimming: 420 },
22 | { date: "2024-07-17", running: 520, swimming: 120 },
23 | { date: "2024-07-18", running: 140, swimming: 550 },
24 | { date: "2024-07-19", running: 600, swimming: 350 },
25 | { date: "2024-07-20", running: 480, swimming: 400 },
26 | ];
27 |
28 | const chartConfig = {
29 | running: {
30 | label: "Running",
31 | color: "hsl(var(--primary))",
32 | },
33 | swimming: {
34 | label: "Swimming",
35 | color: "hsl(var(--chart-2))",
36 | },
37 | } satisfies ChartConfig;
38 |
39 | export default function TooltipChartLabelNone() {
40 | return (
41 |
42 |
43 | Tooltip - No Label
44 | Tooltip with no label.
45 |
46 |
47 |
48 |
49 | {
55 | return new Date(value).toLocaleDateString("en-US", {
56 | weekday: "short",
57 | });
58 | }}
59 | />
60 |
66 |
72 | }
74 | cursor={false}
75 | defaultIndex={1}
76 | />
77 |
78 |
79 |
80 |
81 | );
82 | }
83 |
--------------------------------------------------------------------------------
/src/components/commons/between.tsx:
--------------------------------------------------------------------------------
1 | import clsx from "clsx";
2 | import { ReactNode } from "react";
3 |
4 | interface Props {
5 | w?: string | number;
6 | h?: string | number;
7 | className?: string;
8 | children: ReactNode;
9 | }
10 |
11 | function Between({ w = "full", h = "auto", className, children }: Props) {
12 | return (
13 |
14 | {children}
15 |
16 | );
17 | }
18 |
19 | export default Between;
20 |
--------------------------------------------------------------------------------
/src/components/commons/center.tsx:
--------------------------------------------------------------------------------
1 | import clsx from "clsx";
2 | import { ReactNode } from "react";
3 |
4 | interface Props {
5 | w?: string | number;
6 | h?: string | number;
7 | className?: string;
8 | children: ReactNode;
9 | }
10 |
11 | function Center({ w, h, className, children }: Props) {
12 | return (
13 |
21 | {children}
22 |
23 | );
24 | }
25 |
26 | export default Center;
27 |
--------------------------------------------------------------------------------
/src/components/commons/lang-dropdown.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@components/ui/button";
2 | import {
3 | DropdownMenu,
4 | DropdownMenuContent,
5 | DropdownMenuItem,
6 | DropdownMenuTrigger,
7 | } from "@components/ui/dropdown-menu";
8 | import useUserPreference from "@stores/user-preference";
9 | import clsx from "clsx";
10 | import { Earth } from "lucide-react";
11 | import { useTranslation } from "react-i18next";
12 |
13 | function LangDropdown() {
14 | const { i18n } = useTranslation();
15 | const { changeLang } = useUserPreference();
16 |
17 | const handleChangeLang = (lang: Lang) => {
18 | i18n.changeLanguage(lang);
19 | changeLang(lang);
20 | };
21 |
22 | return (
23 |
24 |
25 |
32 |
33 |
34 | handleChangeLang("en")}
36 | className={clsx(
37 | "cursor-pointer",
38 | i18n.language === "en" &&
39 | "bg-primary text-primary-foreground focus:text-primary-foreground focus:bg-primary"
40 | )}
41 | >
42 | English
43 |
44 | handleChangeLang("mm")}
46 | className={clsx(
47 | "cursor-pointer",
48 | i18n.language === "mm" &&
49 | "bg-primary text-primary-foreground focus:text-primary-foreground focus:bg-primary"
50 | )}
51 | >
52 | Myanmar
53 |
54 |
55 |
56 | );
57 | }
58 |
59 | export default LangDropdown;
60 |
--------------------------------------------------------------------------------
/src/components/commons/logo.tsx:
--------------------------------------------------------------------------------
1 | // interface Props {}
2 |
3 | import { Cannabis } from "lucide-react";
4 |
5 | const Logo = () => {
6 | return (
7 |
8 |
9 |
10 |
11 |
Starter Template
12 |
13 | );
14 | };
15 |
16 | export default Logo;
17 |
--------------------------------------------------------------------------------
/src/components/commons/page-title.tsx:
--------------------------------------------------------------------------------
1 | import Text from "@components/commons/text";
2 |
3 | interface Props {
4 | title: string;
5 | desc?: string;
6 | }
7 |
8 | function PageTitle({ title, desc }: Props) {
9 | return (
10 |
11 |
12 | {title}
13 |
14 | {desc}
15 |
16 | );
17 | }
18 |
19 | export default PageTitle;
20 |
--------------------------------------------------------------------------------
/src/components/commons/text.tsx:
--------------------------------------------------------------------------------
1 | import { cva, type VariantProps } from "class-variance-authority";
2 | import clsx from "clsx";
3 |
4 | const textStyles = cva("font-sans", {
5 | variants: {
6 | size: {
7 | xs: "text-xs",
8 | sm: "text-sm",
9 | md: "text-base",
10 | lg: "text-lg",
11 | xl: "text-xl",
12 | xxl: "text-2xl",
13 | xxxl: "text-3xl",
14 | },
15 | weight: {
16 | normal: "font-normal",
17 | bold: "font-bold",
18 | },
19 | color: {
20 | default: "text-inherit",
21 | primary: "text-primary",
22 | secondary: "text-secondary",
23 | danger: "text-red-500",
24 | },
25 | },
26 | defaultVariants: {
27 | size: "sm",
28 | weight: "normal",
29 | color: "default",
30 | },
31 | });
32 |
33 | type TextProps = VariantProps & {
34 | children: React.ReactNode;
35 | className?: string;
36 | };
37 |
38 | const Text: React.FC = ({
39 | size,
40 | weight,
41 | color,
42 | className,
43 | children,
44 | }) => {
45 | return (
46 |
47 | {children}
48 |
49 | );
50 | };
51 |
52 | export default Text;
53 |
--------------------------------------------------------------------------------
/src/components/data-table/data-table-column-header.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | ArrowDownIcon,
3 | ArrowUpIcon,
4 | CaretSortIcon,
5 | EyeNoneIcon,
6 | } from "@radix-ui/react-icons";
7 | import { Column } from "@tanstack/react-table";
8 |
9 | import { Button } from "@components/ui/button";
10 | import {
11 | DropdownMenu,
12 | DropdownMenuContent,
13 | DropdownMenuItem,
14 | DropdownMenuSeparator,
15 | DropdownMenuTrigger,
16 | } from "@components/ui/dropdown-menu";
17 | import { cn } from "@lib/utils";
18 |
19 | interface DataTableColumnHeaderProps
20 | extends React.HTMLAttributes {
21 | column: Column;
22 | title: string;
23 | }
24 |
25 | export function DataTableColumnHeader({
26 | column,
27 | title,
28 | className,
29 | }: DataTableColumnHeaderProps) {
30 | if (!column.getCanSort()) {
31 | return {title}
;
32 | }
33 |
34 | return (
35 |
36 |
37 |
38 |
52 |
53 |
54 | column.toggleSorting(false)}>
55 |
56 | Asc
57 |
58 | column.toggleSorting(true)}>
59 |
60 | Desc
61 |
62 |
63 | column.toggleVisibility(false)}>
64 |
65 | Hide
66 |
67 |
68 |
69 |
70 | );
71 | }
72 |
--------------------------------------------------------------------------------
/src/components/data-table/data-table-loader.tsx:
--------------------------------------------------------------------------------
1 | import { Skeleton } from "@components/ui/skeleton";
2 | import {
3 | Table as ShadcnTable,
4 | TableBody,
5 | TableCell,
6 | TableHead,
7 | TableHeader,
8 | TableRow,
9 | } from "@components/ui/table";
10 | import { flexRender, Table } from "@tanstack/react-table";
11 |
12 | interface Props {
13 | table: Table;
14 | rowCount: number;
15 | }
16 |
17 | function DataTableLoader({ table, rowCount }: Props) {
18 | const rowCountNumber = new Array(rowCount).fill("");
19 |
20 | return (
21 |
22 |
23 |
24 | {table.getHeaderGroups().map((headerGroup) => (
25 |
26 | {headerGroup.headers.map((header) => {
27 | return (
28 |
29 | {header.isPlaceholder
30 | ? null
31 | : flexRender(
32 | header.column.columnDef.header,
33 | header.getContext()
34 | )}
35 |
36 | );
37 | })}
38 |
39 | ))}
40 |
41 |
42 | {rowCountNumber.map((_, i) => (
43 |
44 | {table.getAllColumns().map((_, i) => (
45 |
46 |
47 |
48 | ))}
49 |
50 | ))}
51 |
52 |
53 |
54 | );
55 | }
56 |
57 | export default DataTableLoader;
58 |
--------------------------------------------------------------------------------
/src/components/data-table/data-table-view-options.tsx:
--------------------------------------------------------------------------------
1 | import { DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu";
2 | import { MixerHorizontalIcon } from "@radix-ui/react-icons";
3 | import { Table } from "@tanstack/react-table";
4 |
5 | import { Button } from "@components/ui/button";
6 | import {
7 | DropdownMenu,
8 | DropdownMenuCheckboxItem,
9 | DropdownMenuContent,
10 | DropdownMenuLabel,
11 | DropdownMenuSeparator,
12 | } from "@components/ui/dropdown-menu";
13 |
14 | interface DataTableViewOptionsProps {
15 | table: Table;
16 | }
17 |
18 | export function DataTableViewOptions({
19 | table,
20 | }: DataTableViewOptionsProps) {
21 | return (
22 |
23 |
24 |
32 |
33 |
34 | Toggle columns
35 |
36 | {table
37 | .getAllColumns()
38 | .filter(
39 | (column) =>
40 | typeof column.accessorFn !== "undefined" && column.getCanHide()
41 | )
42 | .map((column) => {
43 | return (
44 | column.toggleVisibility(!!value)}
49 | >
50 | {column.id}
51 |
52 | );
53 | })}
54 |
55 |
56 | );
57 | }
58 |
--------------------------------------------------------------------------------
/src/components/inputs/checkbox-input.tsx:
--------------------------------------------------------------------------------
1 | import { Checkbox } from "@components/ui/checkbox";
2 | import clsx from "clsx";
3 |
4 | interface Props {
5 | label?: string;
6 | description?: string;
7 | name: string;
8 | form?: any;
9 | }
10 |
11 | function CheckboxInput({ label, description, name, form }: Props) {
12 | return (
13 |
14 |
{
17 | form.clearErrors(name);
18 | form.setValue(name, e);
19 | }}
20 | />
21 |
22 |
31 | {description && (
32 |
38 | {description}
39 |
40 | )}
41 |
42 |
43 | );
44 | }
45 |
46 | export default CheckboxInput;
47 |
--------------------------------------------------------------------------------
/src/components/inputs/checkgroup-Input.tsx:
--------------------------------------------------------------------------------
1 | import { Checkbox } from "@components/ui/checkbox";
2 | import {
3 | FormControl,
4 | FormDescription,
5 | FormField,
6 | FormItem,
7 | FormLabel,
8 | FormMessage,
9 | } from "@components/ui/form";
10 |
11 | interface Props {
12 | label?: string;
13 | description?: string;
14 | withAsterisk?: boolean;
15 | data: DataType[];
16 | name: string;
17 | form?: any;
18 | }
19 |
20 | function CheckGroupInput({
21 | label,
22 | description,
23 | name,
24 | data,
25 | withAsterisk = false,
26 | form,
27 | }: Props) {
28 | return (
29 | (
33 |
34 |
35 |
36 | {label}{" "}
37 | {withAsterisk && *}
38 |
39 | {description && {description}}
40 |
41 | {data.map((d) => (
42 | {
47 | return (
48 |
52 |
53 | {
56 | return checked
57 | ? field.onChange([...(field.value || []), d.value])
58 | : field.onChange(
59 | field.value?.filter(
60 | (value: string) => value !== d.value
61 | )
62 | );
63 | }}
64 | />
65 |
66 | {d.label}
67 |
68 | );
69 | }}
70 | />
71 | ))}
72 |
73 |
74 | )}
75 | />
76 | );
77 | }
78 |
79 | export default CheckGroupInput;
80 |
--------------------------------------------------------------------------------
/src/components/inputs/date-input.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@components/ui/button";
2 | import { Calendar } from "@components/ui/calendar";
3 | import { format } from "date-fns";
4 | import {
5 | FormControl,
6 | FormDescription,
7 | FormField,
8 | FormItem,
9 | FormLabel,
10 | FormMessage,
11 | } from "@components/ui/form";
12 | import { PopoverContent } from "@components/ui/popover";
13 | import { cn } from "@lib/utils";
14 | import { Popover, PopoverTrigger } from "@radix-ui/react-popover";
15 | import { CalendarIcon } from "lucide-react";
16 |
17 | interface Props {
18 | label?: string;
19 | placeholder?: string;
20 | description?: string;
21 | name: string;
22 | withAsterisk?: boolean;
23 | form?: any;
24 | }
25 |
26 | function DateInput({
27 | label,
28 | placeholder,
29 | description,
30 | withAsterisk = false,
31 | name,
32 | form,
33 | }: Props) {
34 | return (
35 | (
39 |
40 | {(label || withAsterisk) && (
41 |
42 | {label}{" "}
43 | {withAsterisk && *}
44 |
45 | )}
46 |
47 |
48 |
49 |
63 |
64 |
65 |
66 | {
70 | field.onChange(e?.toISOString());
71 | }}
72 | disabled={(date) =>
73 | date > new Date() || date < new Date("1900-01-01")
74 | }
75 | initialFocus
76 | />
77 |
78 |
79 | {description && {description}}
80 |
81 |
82 | )}
83 | />
84 | );
85 | }
86 |
87 | export default DateInput;
88 |
--------------------------------------------------------------------------------
/src/components/inputs/password-input.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | FormControl,
3 | FormDescription,
4 | FormField,
5 | FormItem,
6 | FormLabel,
7 | FormMessage,
8 | } from "@components/ui/form";
9 | import { Input } from "@components/ui/input";
10 | import { Eye, EyeOff } from "lucide-react";
11 | import { useState } from "react";
12 |
13 | interface Props {
14 | label?: string;
15 | placeholder?: string;
16 | description?: string;
17 | withAsterisk?: boolean;
18 | name: string;
19 | form?: any;
20 | }
21 |
22 | function PasswordInput({
23 | label,
24 | placeholder,
25 | description,
26 | withAsterisk = false,
27 | name,
28 | form,
29 | }: Props) {
30 | const [visiblePassword, setVisiblePassword] = useState(false);
31 |
32 | const togglePasswordVisibility = () => {
33 | setVisiblePassword((prev) => !prev);
34 | };
35 |
36 | return (
37 | (
41 |
42 | {(label || withAsterisk) && (
43 |
47 | {label}
48 | {withAsterisk && *}
49 |
50 | )}
51 |
52 |
53 |
57 | {!visiblePassword ? (
58 |
59 | ) : (
60 |
61 | )}
62 |
63 |
69 |
70 |
71 |
72 | {description && {description}}
73 |
74 |
75 | )}
76 | />
77 | );
78 | }
79 |
80 | export default PasswordInput;
81 |
--------------------------------------------------------------------------------
/src/components/inputs/radio-input.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | FormControl,
3 | FormField,
4 | FormItem,
5 | FormLabel,
6 | FormMessage,
7 | } from "@components/ui/form";
8 | import { RadioGroup, RadioGroupItem } from "@components/ui/radio-group";
9 |
10 | interface Props {
11 | label?: string;
12 | name: string;
13 | withAsterisk?: boolean;
14 | data: DataType[];
15 | form?: any;
16 | }
17 |
18 | function RadioInput({ label, name, data, withAsterisk = false, form }: Props) {
19 | return (
20 | (
24 |
25 | {(label || withAsterisk) && (
26 |
27 | {label}{" "}
28 | {withAsterisk && *}
29 |
30 | )}
31 |
32 |
37 | {data.map((d) => (
38 |
42 |
43 |
44 |
45 | {d.label}
46 |
47 | ))}
48 |
49 |
50 |
51 |
52 | )}
53 | />
54 | );
55 | }
56 |
57 | export default RadioInput;
58 |
--------------------------------------------------------------------------------
/src/components/inputs/search-input.tsx:
--------------------------------------------------------------------------------
1 | import { Input } from "@components/ui/input";
2 | import { Search } from "lucide-react";
3 |
4 | function SearchInput() {
5 | return (
6 |
7 |
8 |
13 |
14 | );
15 | }
16 |
17 | export default SearchInput;
18 |
--------------------------------------------------------------------------------
/src/components/inputs/select-input.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | FormControl,
3 | FormDescription,
4 | FormField,
5 | FormItem,
6 | FormLabel,
7 | FormMessage,
8 | } from "@components/ui/form";
9 | import {
10 | Select,
11 | SelectContent,
12 | SelectItem,
13 | SelectTrigger,
14 | SelectValue,
15 | } from "@components/ui/select";
16 |
17 | interface Props {
18 | label?: string;
19 | placeholder?: string;
20 | description?: string;
21 | data: DataType[];
22 | withAsterisk?: boolean;
23 | name: string;
24 | form?: any;
25 | isLoading?: boolean;
26 | className?: string;
27 | }
28 |
29 | function SelectInput({
30 | label,
31 | placeholder,
32 | withAsterisk = false,
33 | description,
34 | data,
35 | name,
36 | form,
37 | isLoading = false,
38 | className,
39 | }: Props) {
40 | return (
41 | (
45 |
46 | {(label || withAsterisk) && (
47 |
48 | {label}{" "}
49 | {withAsterisk && *}
50 |
51 | )}
52 |
74 | {description && {description}}
75 |
76 |
77 | )}
78 | />
79 | );
80 | }
81 |
82 | export default SelectInput;
83 |
--------------------------------------------------------------------------------
/src/components/inputs/text-input.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | FormControl,
3 | FormDescription,
4 | FormField,
5 | FormItem,
6 | FormLabel,
7 | FormMessage,
8 | } from "@components/ui/form";
9 | import { Input } from "@components/ui/input";
10 |
11 | interface Props {
12 | label?: string;
13 | placeholder?: string;
14 | description?: string;
15 | withAsterisk?: boolean;
16 | name: string;
17 | form?: any;
18 | }
19 |
20 | function TextInput({
21 | label,
22 | placeholder,
23 | description,
24 | withAsterisk = false,
25 | name,
26 | form,
27 | }: Props) {
28 | return (
29 | (
33 |
34 | {(label || withAsterisk) && (
35 |
36 | {label}{" "}
37 | {withAsterisk && *}
38 |
39 | )}
40 |
41 |
42 |
43 |
44 | {description && {description}}
45 |
46 |
47 | )}
48 | />
49 | );
50 | }
51 |
52 | export default TextInput;
53 |
--------------------------------------------------------------------------------
/src/components/inputs/textarea-input.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | FormControl,
3 | FormDescription,
4 | FormField,
5 | FormItem,
6 | FormLabel,
7 | FormMessage,
8 | } from "@components/ui/form";
9 | import { Textarea } from "@components/ui/textarea";
10 |
11 | interface Props {
12 | label?: string;
13 | placeholder?: string;
14 | description?: string;
15 | withAsterisk?: boolean;
16 | name: string;
17 | form?: any;
18 | }
19 |
20 | function TextareaInput({
21 | label,
22 | placeholder,
23 | description,
24 | withAsterisk = false,
25 | name,
26 | form,
27 | }: Props) {
28 | return (
29 | {
33 | return (
34 |
35 | {(label || withAsterisk) && (
36 |
37 | {label}{" "}
38 | {withAsterisk && (
39 | *
40 | )}
41 |
42 | )}
43 |
44 |
49 |
50 | {description && {description}}
51 |
52 |
53 | );
54 | }}
55 | />
56 | );
57 | }
58 |
59 | export default TextareaInput;
60 |
--------------------------------------------------------------------------------
/src/components/loaders/page-loader.tsx:
--------------------------------------------------------------------------------
1 | function PageLoader() {
2 | return (
3 |
21 | );
22 | }
23 |
24 | export default PageLoader;
25 |
--------------------------------------------------------------------------------
/src/components/modals/demo.tsx:
--------------------------------------------------------------------------------
1 | import Text from "@components/commons/text";
2 |
3 | function DemoModal() {
4 | return (
5 |
6 |
7 |
8 | The Coldest Sunset
9 |
10 |
11 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatibus
12 | quia, nulla! Maiores et perferendis eaque, exercitationem praesentium
13 | nihil.
14 |
15 |
16 |
17 | );
18 | }
19 |
20 | export default DemoModal;
21 |
--------------------------------------------------------------------------------
/src/components/modals/idle-confirmation.tsx:
--------------------------------------------------------------------------------
1 | import Text from "@components/commons/text";
2 | import { Button } from "@components/ui/button";
3 | import { useModal } from "@saimin/react-modal-manager";
4 |
5 | interface Props {
6 | onLogout: () => void;
7 | }
8 |
9 | function IdleConfirmation({ onLogout }: Props) {
10 | const { closeAll } = useModal();
11 |
12 | const handleLogout = () => {
13 | onLogout();
14 | closeAll();
15 | };
16 |
17 | return (
18 |
19 |
20 | You have been idled
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 | );
34 | }
35 |
36 | export default IdleConfirmation;
37 |
--------------------------------------------------------------------------------
/src/components/modals/logout-confirmation.tsx:
--------------------------------------------------------------------------------
1 | import Text from "@components/commons/text";
2 | import { Button } from "@components/ui/button";
3 | import { useModal } from "@saimin/react-modal-manager";
4 |
5 | interface Props {
6 | onConfirm: () => void;
7 | }
8 |
9 | function LogoutConfirmation({ onConfirm }: Props) {
10 | const { close } = useModal();
11 |
12 | const handleCancel = () => {
13 | close("logout-confirmation");
14 | };
15 |
16 | const handleLogout = () => {
17 | onConfirm();
18 | close("logout-confirmation");
19 | };
20 |
21 | return (
22 |
23 |
24 | Are you sure to exit?
25 |
26 |
27 |
28 |
29 |
30 |
33 |
34 |
35 |
36 |
37 | );
38 | }
39 |
40 | export default LogoutConfirmation;
41 |
--------------------------------------------------------------------------------
/src/components/selects/category-select.tsx:
--------------------------------------------------------------------------------
1 | import { useGetAllProductCategories } from "@apis/queries/category";
2 | import SelectInput from "@components/inputs/select-input";
3 |
4 | interface Props {
5 | label?: string;
6 | placeholder?: string;
7 | description?: string;
8 | withAsterisk?: boolean;
9 | name: string;
10 | form?: any;
11 | isLoading?: boolean;
12 | className?: string;
13 | }
14 |
15 | function CategorySelect(props: Props) {
16 | const { data, isLoading } = useGetAllProductCategories();
17 |
18 | return ;
19 | }
20 |
21 | export default CategorySelect;
22 |
--------------------------------------------------------------------------------
/src/components/theme/theme-provider.tsx:
--------------------------------------------------------------------------------
1 | import { createContext, useContext, useEffect, useState } from "react";
2 | import { ModalProvider } from "@saimin/react-modal-manager";
3 | import { TooltipProvider } from "@components/ui/tooltip";
4 |
5 | type Theme = "dark" | "light" | "system";
6 |
7 | type ThemeProviderProps = {
8 | children: React.ReactNode;
9 | defaultTheme?: Theme;
10 | storageKey?: string;
11 | };
12 |
13 | type ThemeProviderState = {
14 | theme: Theme;
15 | setTheme: (theme: Theme) => void;
16 | };
17 |
18 | const initialState: ThemeProviderState = {
19 | theme: "system",
20 | setTheme: () => null,
21 | };
22 |
23 | const ThemeProviderContext = createContext(initialState);
24 |
25 | export function ThemeProvider({
26 | children,
27 | defaultTheme = "system",
28 | storageKey = "vite-ui-theme",
29 | ...props
30 | }: ThemeProviderProps) {
31 | const [theme, setTheme] = useState(
32 | () => (localStorage.getItem(storageKey) as Theme) || defaultTheme
33 | );
34 |
35 | useEffect(() => {
36 | const root = window.document.documentElement;
37 |
38 | root.classList.remove("light", "dark");
39 |
40 | if (theme === "system") {
41 | const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
42 | .matches
43 | ? "dark"
44 | : "light";
45 |
46 | root.classList.add(systemTheme);
47 | return;
48 | }
49 |
50 | root.classList.add(theme);
51 | }, [theme]);
52 |
53 | const value = {
54 | theme,
55 | setTheme: (theme: Theme) => {
56 | localStorage.setItem(storageKey, theme);
57 | setTheme(theme);
58 | },
59 | };
60 |
61 | return (
62 |
63 |
64 | {children}
65 |
66 |
67 | );
68 | }
69 |
70 | // eslint-disable-next-line react-refresh/only-export-components
71 | export const useTheme = () => {
72 | const context = useContext(ThemeProviderContext);
73 |
74 | if (context === undefined)
75 | throw new Error("useTheme must be used within a ThemeProvider");
76 |
77 | return context;
78 | };
79 |
--------------------------------------------------------------------------------
/src/components/ui/avatar.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as AvatarPrimitive from "@radix-ui/react-avatar"
3 |
4 | import { cn } from "@lib/utils"
5 |
6 | const Avatar = React.forwardRef<
7 | React.ElementRef,
8 | React.ComponentPropsWithoutRef
9 | >(({ className, ...props }, ref) => (
10 |
18 | ))
19 | Avatar.displayName = AvatarPrimitive.Root.displayName
20 |
21 | const AvatarImage = React.forwardRef<
22 | React.ElementRef,
23 | React.ComponentPropsWithoutRef
24 | >(({ className, ...props }, ref) => (
25 |
30 | ))
31 | AvatarImage.displayName = AvatarPrimitive.Image.displayName
32 |
33 | const AvatarFallback = React.forwardRef<
34 | React.ElementRef,
35 | React.ComponentPropsWithoutRef
36 | >(({ className, ...props }, ref) => (
37 |
45 | ))
46 | AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
47 |
48 | export { Avatar, AvatarImage, AvatarFallback }
49 |
--------------------------------------------------------------------------------
/src/components/ui/badge.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { cva, type VariantProps } from "class-variance-authority";
3 |
4 | import { cn } from "@lib/utils";
5 |
6 | const badgeVariants = cva(
7 | "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
8 | {
9 | variants: {
10 | variant: {
11 | default:
12 | "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
13 | secondary:
14 | "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
15 | destructive:
16 | "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
17 | outline: "text-foreground",
18 | },
19 | },
20 | defaultVariants: {
21 | variant: "default",
22 | },
23 | }
24 | );
25 |
26 | export interface BadgeProps
27 | extends React.HTMLAttributes,
28 | VariantProps {}
29 |
30 | function Badge({ className, variant, ...props }: BadgeProps) {
31 | return (
32 |
33 | );
34 | }
35 |
36 | export { Badge, badgeVariants };
37 |
--------------------------------------------------------------------------------
/src/components/ui/button.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { Slot } from "@radix-ui/react-slot";
3 | import { cva, type VariantProps } from "class-variance-authority";
4 |
5 | import { cn } from "@lib/utils";
6 | import { Loader2 } from "lucide-react";
7 |
8 | const buttonVariants = cva(
9 | "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
10 | {
11 | variants: {
12 | variant: {
13 | default:
14 | "bg-primary text-primary-foreground shadow hover:bg-primary/90",
15 | destructive:
16 | "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
17 | outline:
18 | "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
19 | secondary:
20 | "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
21 | ghost: "hover:bg-accent hover:text-accent-foreground",
22 | link: "text-primary underline-offset-4 hover:underline",
23 | },
24 | size: {
25 | default: "h-9 px-4 py-2",
26 | sm: "h-8 rounded-md px-3 text-xs",
27 | lg: "h-10 rounded-md px-8",
28 | icon: "h-9 w-9",
29 | },
30 | },
31 | defaultVariants: {
32 | variant: "default",
33 | size: "default",
34 | },
35 | }
36 | );
37 |
38 | export interface ButtonProps
39 | extends React.ButtonHTMLAttributes,
40 | VariantProps {
41 | asChild?: boolean;
42 | loading?: boolean;
43 | fullWidth?: boolean;
44 | }
45 |
46 | const Button = React.forwardRef(
47 | (
48 | {
49 | className,
50 | variant,
51 | size,
52 | asChild = false,
53 | loading = false,
54 | fullWidth = false,
55 | ...props
56 | },
57 | ref
58 | ) => {
59 | const Comp = asChild ? Slot : "button";
60 | return (
61 |
70 | {loading && }
71 | {props.children}
72 |
73 | );
74 | }
75 | );
76 | Button.displayName = "Button";
77 |
78 | // eslint-disable-next-line react-refresh/only-export-components
79 | export { Button, buttonVariants };
80 |
--------------------------------------------------------------------------------
/src/components/ui/card.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import { cn } from "@lib/utils";
4 |
5 | const Card = React.forwardRef<
6 | HTMLDivElement,
7 | React.HTMLAttributes
8 | >(({ className, ...props }, ref) => (
9 |
17 | ));
18 | Card.displayName = "Card";
19 |
20 | const CardHeader = React.forwardRef<
21 | HTMLDivElement,
22 | React.HTMLAttributes
23 | >(({ className, ...props }, ref) => (
24 |
29 | ));
30 | CardHeader.displayName = "CardHeader";
31 |
32 | const CardTitle = React.forwardRef<
33 | HTMLParagraphElement,
34 | React.HTMLAttributes
35 | >(({ className, ...props }, ref) => (
36 |
41 | ));
42 | CardTitle.displayName = "CardTitle";
43 |
44 | const CardDescription = React.forwardRef<
45 | HTMLParagraphElement,
46 | React.HTMLAttributes
47 | >(({ className, ...props }, ref) => (
48 |
53 | ));
54 | CardDescription.displayName = "CardDescription";
55 |
56 | const CardContent = React.forwardRef<
57 | HTMLDivElement,
58 | React.HTMLAttributes
59 | >(({ className, ...props }, ref) => (
60 |
61 | ));
62 | CardContent.displayName = "CardContent";
63 |
64 | const CardFooter = React.forwardRef<
65 | HTMLDivElement,
66 | React.HTMLAttributes
67 | >(({ className, ...props }, ref) => (
68 |
73 | ));
74 | CardFooter.displayName = "CardFooter";
75 |
76 | export {
77 | Card,
78 | CardHeader,
79 | CardFooter,
80 | CardTitle,
81 | CardDescription,
82 | CardContent,
83 | };
84 |
--------------------------------------------------------------------------------
/src/components/ui/checkbox.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
3 | import { CheckIcon } from "@radix-ui/react-icons"
4 |
5 | import { cn } from "@lib/utils"
6 |
7 | const Checkbox = React.forwardRef<
8 | React.ElementRef,
9 | React.ComponentPropsWithoutRef
10 | >(({ className, ...props }, ref) => (
11 |
19 |
22 |
23 |
24 |
25 | ))
26 | Checkbox.displayName = CheckboxPrimitive.Root.displayName
27 |
28 | export { Checkbox }
29 |
--------------------------------------------------------------------------------
/src/components/ui/input.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import { cn } from "@lib/utils";
4 |
5 | export interface InputProps
6 | extends React.InputHTMLAttributes {}
7 |
8 | const Input = React.forwardRef(
9 | ({ className, type, ...props }, ref) => {
10 | return (
11 |
20 | );
21 | }
22 | );
23 | Input.displayName = "Input";
24 |
25 | export { Input };
26 |
--------------------------------------------------------------------------------
/src/components/ui/label.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as LabelPrimitive from "@radix-ui/react-label"
3 | import { cva, type VariantProps } from "class-variance-authority"
4 |
5 | import { cn } from "@lib/utils"
6 |
7 | const labelVariants = cva(
8 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
9 | )
10 |
11 | const Label = React.forwardRef<
12 | React.ElementRef,
13 | React.ComponentPropsWithoutRef &
14 | VariantProps
15 | >(({ className, ...props }, ref) => (
16 |
21 | ))
22 | Label.displayName = LabelPrimitive.Root.displayName
23 |
24 | export { Label }
25 |
--------------------------------------------------------------------------------
/src/components/ui/popover.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as PopoverPrimitive from "@radix-ui/react-popover";
3 |
4 | import { cn } from "@lib/utils";
5 |
6 | const Popover = PopoverPrimitive.Root;
7 |
8 | const PopoverTrigger = PopoverPrimitive.Trigger;
9 |
10 | const PopoverAnchor = PopoverPrimitive.Anchor;
11 |
12 | const PopoverContent = React.forwardRef<
13 | React.ElementRef,
14 | React.ComponentPropsWithoutRef
15 | >(({ className, align = "center", sideOffset = 2, ...props }, ref) => (
16 |
17 |
27 |
28 | ));
29 | PopoverContent.displayName = PopoverPrimitive.Content.displayName;
30 |
31 | export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
32 |
--------------------------------------------------------------------------------
/src/components/ui/radio-group.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { CheckIcon } from "@radix-ui/react-icons"
3 | import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
4 |
5 | import { cn } from "@lib/utils"
6 |
7 | const RadioGroup = React.forwardRef<
8 | React.ElementRef,
9 | React.ComponentPropsWithoutRef
10 | >(({ className, ...props }, ref) => {
11 | return (
12 |
17 | )
18 | })
19 | RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
20 |
21 | const RadioGroupItem = React.forwardRef<
22 | React.ElementRef,
23 | React.ComponentPropsWithoutRef
24 | >(({ className, ...props }, ref) => {
25 | return (
26 |
34 |
35 |
36 |
37 |
38 | )
39 | })
40 | RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
41 |
42 | export { RadioGroup, RadioGroupItem }
43 |
--------------------------------------------------------------------------------
/src/components/ui/separator.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as SeparatorPrimitive from "@radix-ui/react-separator"
3 |
4 | import { cn } from "@lib/utils"
5 |
6 | const Separator = React.forwardRef<
7 | React.ElementRef,
8 | React.ComponentPropsWithoutRef
9 | >(
10 | (
11 | { className, orientation = "horizontal", decorative = true, ...props },
12 | ref
13 | ) => (
14 |
25 | )
26 | )
27 | Separator.displayName = SeparatorPrimitive.Root.displayName
28 |
29 | export { Separator }
30 |
--------------------------------------------------------------------------------
/src/components/ui/skeleton.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from "@lib/utils"
2 |
3 | function Skeleton({
4 | className,
5 | ...props
6 | }: React.HTMLAttributes) {
7 | return (
8 |
12 | )
13 | }
14 |
15 | export { Skeleton }
16 |
--------------------------------------------------------------------------------
/src/components/ui/slider.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as SliderPrimitive from "@radix-ui/react-slider"
3 |
4 | import { cn } from "@lib/utils"
5 |
6 | const Slider = React.forwardRef<
7 | React.ElementRef,
8 | React.ComponentPropsWithoutRef
9 | >(({ className, ...props }, ref) => (
10 |
18 |
19 |
20 |
21 |
22 |
23 | ))
24 | Slider.displayName = SliderPrimitive.Root.displayName
25 |
26 | export { Slider }
27 |
--------------------------------------------------------------------------------
/src/components/ui/sonner.tsx:
--------------------------------------------------------------------------------
1 | import { useTheme } from "next-themes";
2 | import { Toaster as Sonner } from "sonner";
3 |
4 | type ToasterProps = React.ComponentProps;
5 |
6 | const Toaster = ({ ...props }: ToasterProps) => {
7 | const { theme = "system" } = useTheme();
8 |
9 | return (
10 |
28 | );
29 | };
30 |
31 | export { Toaster };
32 |
--------------------------------------------------------------------------------
/src/components/ui/tabs.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as TabsPrimitive from "@radix-ui/react-tabs";
3 |
4 | import { cn } from "@lib/utils";
5 |
6 | const Tabs = TabsPrimitive.Root;
7 |
8 | const TabsList = React.forwardRef<
9 | React.ElementRef,
10 | React.ComponentPropsWithoutRef
11 | >(({ className, ...props }, ref) => (
12 |
20 | ));
21 | TabsList.displayName = TabsPrimitive.List.displayName;
22 |
23 | const TabsTrigger = React.forwardRef<
24 | React.ElementRef,
25 | React.ComponentPropsWithoutRef
26 | >(({ className, ...props }, ref) => (
27 |
35 | ));
36 | TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
37 |
38 | const TabsContent = React.forwardRef<
39 | React.ElementRef,
40 | React.ComponentPropsWithoutRef
41 | >(({ className, ...props }, ref) => (
42 |
50 | ));
51 | TabsContent.displayName = TabsPrimitive.Content.displayName;
52 |
53 | export { Tabs, TabsList, TabsTrigger, TabsContent };
54 |
--------------------------------------------------------------------------------
/src/components/ui/textarea.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import { cn } from "@lib/utils"
4 |
5 | export interface TextareaProps
6 | extends React.TextareaHTMLAttributes {}
7 |
8 | const Textarea = React.forwardRef(
9 | ({ className, ...props }, ref) => {
10 | return (
11 |
19 | )
20 | }
21 | )
22 | Textarea.displayName = "Textarea"
23 |
24 | export { Textarea }
25 |
--------------------------------------------------------------------------------
/src/components/ui/tooltip.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as TooltipPrimitive from "@radix-ui/react-tooltip";
3 |
4 | import { cn } from "@lib/utils";
5 |
6 | const TooltipProvider = TooltipPrimitive.Provider;
7 |
8 | const Tooltip = TooltipPrimitive.Root;
9 |
10 | const TooltipTrigger = TooltipPrimitive.Trigger;
11 |
12 | const TooltipContent = React.forwardRef<
13 | React.ElementRef,
14 | React.ComponentPropsWithoutRef
15 | >(({ className, sideOffset = 4, ...props }, ref) => (
16 |
25 | ));
26 | TooltipContent.displayName = TooltipPrimitive.Content.displayName;
27 |
28 | export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
29 |
--------------------------------------------------------------------------------
/src/configs/menus.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | ChartColumnIncreasing,
3 | CircleGauge,
4 | FileBox,
5 | FileText,
6 | ShieldX,
7 | Table2,
8 | } from "lucide-react";
9 |
10 | const menus = [
11 | {
12 | name: "sidebar.dashboard",
13 | icon: ,
14 | route: "/dashboard",
15 | },
16 | {
17 | name: "sidebar.form",
18 | icon: ,
19 | route: "/forms",
20 | },
21 | {
22 | name: "sidebar.table",
23 | icon: ,
24 | route: "/table",
25 | },
26 | {
27 | name: "sidebar.charts",
28 | icon: ,
29 | route: "/charts",
30 | },
31 | {
32 | name: "sidebar.errPages",
33 | icon: ,
34 | route: "error-pages",
35 | childs: [
36 | {
37 | name: "404 page",
38 | icon: ,
39 | route: "404",
40 | },
41 | {
42 | name: "500 page",
43 | icon: ,
44 | route: "500",
45 | },
46 | ],
47 | },
48 | {
49 | name: "sidebar.modals",
50 | icon: ,
51 | route: "/modals",
52 | },
53 | ];
54 |
55 | export default menus;
56 |
--------------------------------------------------------------------------------
/src/configs/routes.tsx:
--------------------------------------------------------------------------------
1 | import AuthLayout from "@layouts/auth/auth-layout";
2 | import { DashboardLayout } from "@layouts/dashboard/dashboard-layout";
3 | import RootLayout from "@layouts/root/root-layout";
4 | import {
5 | Charts,
6 | Dashboard,
7 | Error404,
8 | Error500,
9 | Form,
10 | Login,
11 | Modals,
12 | TableCreatePage,
13 | TableList,
14 | } from "@pages/index";
15 | import { createBrowserRouter, Navigate } from "react-router-dom";
16 |
17 | export const router = createBrowserRouter([
18 | {
19 | path: "/",
20 | element: ,
21 | children: [
22 | {
23 | path: "",
24 | element: ,
25 | children: [
26 | {
27 | index: true,
28 | element: ,
29 | },
30 | {
31 | index: true,
32 | path: "dashboard",
33 | element: ,
34 | },
35 | {
36 | path: "forms",
37 | element: ,
38 | },
39 | {
40 | path: "table",
41 | element: ,
42 | },
43 | {
44 | path: "table/create",
45 | element: ,
46 | },
47 | {
48 | path: "charts",
49 | element: ,
50 | },
51 | {
52 | path: "modals",
53 | element: ,
54 | },
55 | {
56 | path: "404",
57 | element: ,
58 | },
59 | {
60 | path: "500",
61 | element: ,
62 | },
63 | ],
64 | },
65 | {
66 | path: "auth",
67 | element: ,
68 | children: [
69 | {
70 | index: true,
71 | path: "login",
72 | element: ,
73 | },
74 | ],
75 | },
76 | ],
77 | },
78 | {
79 | path: "/*",
80 | element: ,
81 | },
82 | ]);
83 |
--------------------------------------------------------------------------------
/src/configs/vars.tsx:
--------------------------------------------------------------------------------
1 | export const TOKEN = "token";
2 | export const REFRESH_TOKEN = "refresh-token";
3 |
4 | export const ADMIN = {
5 | username: "admin",
6 | password: "password",
7 | };
8 |
--------------------------------------------------------------------------------
/src/helpers/form-schemas-validators.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | export const requiredString = (message: string) => {
4 | return z.string().min(1, {
5 | message,
6 | });
7 | };
8 |
9 | export const requiredNumber = (message: string) => {
10 | return z.number().gte(1, { message });
11 | };
12 |
13 | export const requiredCheckGroup = (message: string) => {
14 | return z.array(z.string()).refine((value) => value.some((item) => item), {
15 | message,
16 | });
17 | };
18 |
19 | export const requiredTrueValue = (message: string) => {
20 | return z.literal(true).refine((value) => value === true, {
21 | message,
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/src/hooks/use-auth-operations.ts:
--------------------------------------------------------------------------------
1 | // import { useNavigate } from "react-router-dom";
2 | import Cookie from "js-cookie";
3 | import { REFRESH_TOKEN, TOKEN } from "@configs/vars";
4 | import { useNavigate } from "react-router-dom";
5 |
6 | /**
7 | * useAuthOperations hook that provides authentication & authorization methods
8 | */
9 | const useAuthOperations = () => {
10 | const navigate = useNavigate();
11 |
12 | function login(value: Record) {
13 | Cookie.set(TOKEN, value.token);
14 | Cookie.set(REFRESH_TOKEN, value.refreshToken);
15 | navigate("/");
16 | }
17 |
18 | function logout() {
19 | Cookie.remove(TOKEN);
20 | Cookie.remove(REFRESH_TOKEN);
21 | navigate("/auth/login");
22 | }
23 |
24 | return { login, logout };
25 | };
26 |
27 | export default useAuthOperations;
28 |
--------------------------------------------------------------------------------
/src/hooks/use-auth.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { useNavigate } from "react-router-dom";
3 | import Cookie from "js-cookie";
4 | import { TOKEN } from "@configs/vars";
5 |
6 | /**
7 | * useAuth hook to protect private routes
8 | */
9 | const useAuth = () => {
10 | const navigate = useNavigate();
11 | const isLoggined = Cookie.get(TOKEN);
12 |
13 | useEffect(() => {
14 | if (!isLoggined) {
15 | navigate("/auth/login");
16 | }
17 | // eslint-disable-next-line react-hooks/exhaustive-deps
18 | }, [isLoggined]);
19 | };
20 |
21 | export default useAuth;
22 |
--------------------------------------------------------------------------------
/src/hooks/use-report.ts:
--------------------------------------------------------------------------------
1 | import * as XLSX from "xlsx";
2 |
3 | const useReport = () => {
4 | /**
5 | *
6 | * @param data data that you want to export in object array format
7 | * @param filename filename of your exported file
8 | */
9 | const generateExcel = (data: Record[], filename: string) => {
10 | // Convert JSON to a worksheet
11 | const worksheet = XLSX.utils.json_to_sheet(data);
12 |
13 | // Create a new workbook and append the worksheet
14 | const workbook = XLSX.utils.book_new();
15 | XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
16 |
17 | // Generate the Excel file and trigger a download
18 | XLSX.writeFile(workbook, `${filename}.xlsx`);
19 | };
20 |
21 | return { generateExcel };
22 | };
23 |
24 | export default useReport;
25 |
--------------------------------------------------------------------------------
/src/hooks/use-unauth.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { useNavigate } from "react-router-dom";
3 | import Cookie from "js-cookie";
4 | import { TOKEN } from "@configs/vars";
5 |
6 | /**
7 | * useUnauth hook to protect auth routes after login
8 | */
9 | const useUnauth = () => {
10 | const navigate = useNavigate();
11 | const isLoggined = Cookie.get(TOKEN);
12 |
13 | useEffect(() => {
14 | if (isLoggined) {
15 | navigate("/");
16 | }
17 | // eslint-disable-next-line react-hooks/exhaustive-deps
18 | }, [isLoggined]);
19 | };
20 |
21 | export default useUnauth;
22 |
--------------------------------------------------------------------------------
/src/hooks/use-url-query.ts:
--------------------------------------------------------------------------------
1 | function useUrlQuery() {
2 | const queryString = window.location.search;
3 | const urlParams = new URLSearchParams(queryString);
4 |
5 | function getAllParams() {
6 | const params: Record = {};
7 | urlParams.forEach((value, key) => {
8 | params[key] = value;
9 | });
10 |
11 | return params;
12 | }
13 |
14 | function getParam(name: string) {
15 | return urlParams.get(name);
16 | }
17 |
18 | function setParam(name: string, value: string) {
19 | urlParams.set(name, value);
20 | const updatedSearch = `?${urlParams.toString()}`;
21 | window.history.replaceState(
22 | {},
23 | "",
24 | `${window.location.pathname}${updatedSearch}`
25 | );
26 | }
27 |
28 | function removeParam(name: string) {
29 | urlParams.delete(name);
30 | const updatedSearch = `?${urlParams.toString()}`;
31 | window.history.replaceState(
32 | {},
33 | "",
34 | `${window.location.pathname}${updatedSearch}`
35 | );
36 | }
37 |
38 | return { getAllParams, getParam, setParam, removeParam };
39 | }
40 |
41 | export default useUrlQuery;
42 |
--------------------------------------------------------------------------------
/src/i18n.ts:
--------------------------------------------------------------------------------
1 | import i18n from "i18next";
2 | import { initReactI18next } from "react-i18next";
3 | import en from "@assets/translations/en.json";
4 | import mm from "@assets/translations/mm.json";
5 | import useUserPreference from "@stores/user-preference";
6 |
7 | const resources = {
8 | en: {
9 | translation: en,
10 | },
11 | mm: {
12 | translation: mm,
13 | },
14 | };
15 |
16 | i18n.use(initReactI18next).init({
17 | resources,
18 | lng: useUserPreference.getState().lang || "en",
19 | fallbackLng: useUserPreference.getState().lang || "en",
20 | interpolation: {
21 | escapeValue: false,
22 | },
23 | });
24 |
25 | export default i18n;
26 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer base {
6 | :root {
7 | --background: 0 0% 100%;
8 | --foreground: 222.2 84% 4.9%;
9 | --card: 0 0% 100%;
10 | --card-foreground: 222.2 84% 4.9%;
11 | --popover: 0 0% 100%;
12 | --popover-foreground: 222.2 84% 4.9%;
13 | --primary: 330 100% 70%; /* Pink color updated to match #ff66c4 */
14 | --primary-foreground: 210 40% 98%;
15 | --secondary: 210 40% 96.1%;
16 | --secondary-foreground: 222.2 47.4% 11.2%;
17 | --muted: 210 40% 96.1%;
18 | --muted-foreground: 215.4 16.3% 46.9%;
19 | --accent: 210 40% 96.1%;
20 | --accent-foreground: 222.2 47.4% 11.2%;
21 | --destructive: 0 84.2% 60.2%;
22 | --destructive-foreground: 210 40% 98%;
23 | --border: 214.3 31.8% 91.4%;
24 | --input: 214.3 31.8% 91.4%;
25 | --ring: 330 100% 70%; /* Pink color updated to match #ff66c4 */
26 | --radius: 0.5rem;
27 | --chart-1: 330 100% 70%;
28 | --chart-2: 300 100% 25%;
29 | --chart-3: 240 100% 27%;
30 | --chart-4: 120 100% 20%;
31 | --chart-5: 0 59% 41%;
32 | }
33 |
34 | .dark {
35 | --background: 222.2 84% 4.9%;
36 | --foreground: 210 40% 98%;
37 | --card: 222.2 84% 4.9%;
38 | --card-foreground: 210 40% 98%;
39 | --popover: 222.2 84% 4.9%;
40 | --popover-foreground: 210 40% 98%;
41 | --primary: 330 100% 70%; /* Pink color updated to match #ff66c4 */
42 | --primary-foreground: 222.2 47.4% 11.2%;
43 | --secondary: 217.2 32.6% 17.5%;
44 | --secondary-foreground: 210 40% 98%;
45 | --muted: 217.2 32.6% 17.5%;
46 | --muted-foreground: 215 20.2% 65.1%;
47 | --accent: 217.2 32.6% 17.5%;
48 | --accent-foreground: 210 40% 98%;
49 | --destructive: 0 62.8% 30.6%;
50 | --destructive-foreground: 210 40% 98%;
51 | --border: 217.2 32.6% 17.5%;
52 | --input: 217.2 32.6% 17.5%;
53 | --ring: 330 100% 70%; /* Pink color updated to match #ff66c4 */
54 | --chart-1: 330 100% 70%;
55 | --chart-2: 300 100% 25%;
56 | --chart-3: 240 100% 27%;
57 | --chart-4: 120 100% 20%;
58 | --chart-5: 0 59% 41%;
59 | }
60 | }
61 |
62 | @layer base {
63 | * {
64 | @apply border-border;
65 | }
66 | body {
67 | @apply bg-background text-foreground;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/layouts/auth/auth-layout.tsx:
--------------------------------------------------------------------------------
1 | import Center from "@components/commons/center";
2 | import { Outlet } from "react-router-dom";
3 | import { Header } from "./components";
4 | import useUnauth from "@hooks/use-unauth";
5 |
6 | function AuthLayout() {
7 | useUnauth();
8 |
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 | );
17 | }
18 |
19 | export default AuthLayout;
20 |
--------------------------------------------------------------------------------
/src/layouts/auth/components/header.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@components/ui/button";
2 | import { Moon, Sun } from "lucide-react";
3 | import clsx from "clsx";
4 | import LangDropdown from "@components/commons/lang-dropdown";
5 | import { useTheme } from "@components/theme/theme-provider";
6 | import Logo from "@components/commons/logo";
7 |
8 | export function Header() {
9 | const { setTheme, theme } = useTheme();
10 |
11 | const handleToggleTheme = () => {
12 | if (theme === "dark") {
13 | setTheme("light");
14 | } else {
15 | setTheme("dark");
16 | }
17 | };
18 |
19 | return (
20 |
47 | );
48 | }
49 |
--------------------------------------------------------------------------------
/src/layouts/auth/components/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./header";
2 |
--------------------------------------------------------------------------------
/src/layouts/dashboard/components/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./header";
2 | export * from "./sidebar";
3 |
--------------------------------------------------------------------------------
/src/layouts/dashboard/components/sidebar-footer.tsx:
--------------------------------------------------------------------------------
1 | import { Settings2 } from "lucide-react";
2 | import SidebarItem from "./sidebar-item";
3 |
4 | function SidebarFooter() {
5 | return (
6 |
7 | }
9 | name="Settings"
10 | route="settings"
11 | />
12 |
13 | );
14 | }
15 |
16 | export default SidebarFooter;
17 |
--------------------------------------------------------------------------------
/src/layouts/dashboard/components/sidebar-header.tsx:
--------------------------------------------------------------------------------
1 | import { Cannabis } from "lucide-react";
2 | import Text from "@components/commons/text";
3 | import useUserPreference from "@stores/user-preference";
4 | import clsx from "clsx";
5 |
6 | function SidebarHeader() {
7 | const { sidebarCollapsed } = useUserPreference();
8 |
9 | return (
10 |
16 |
21 |
22 |
23 |
24 | {!sidebarCollapsed && (
25 |
26 | Starter Template
27 |
28 | )}
29 |
30 | );
31 | }
32 |
33 | export default SidebarHeader;
34 |
--------------------------------------------------------------------------------
/src/layouts/dashboard/components/sidebar.tsx:
--------------------------------------------------------------------------------
1 | import SidebarItem from "./sidebar-item";
2 | import menus from "@configs/menus";
3 | import SidebarHeader from "./sidebar-header";
4 | import SidebarFooter from "./sidebar-footer";
5 | import { ChevronLeft, ChevronRight } from "lucide-react";
6 | import useUserPreference from "@stores/user-preference";
7 | import clsx from "clsx";
8 |
9 | export function Sidebar() {
10 | const { sidebarCollapsed, toggleSidebar } = useUserPreference();
11 |
12 | return (
13 | <>
14 |
38 |
39 |
46 | {sidebarCollapsed ? (
47 |
48 | ) : (
49 |
50 | )}
51 |
52 | >
53 | );
54 | }
55 |
--------------------------------------------------------------------------------
/src/layouts/dashboard/dashboard-layout.tsx:
--------------------------------------------------------------------------------
1 | import { Outlet } from "react-router-dom";
2 | import clsx from "clsx";
3 | import { Header, Sidebar } from "./components";
4 | import useUserPreference from "@stores/user-preference";
5 | import { IdleTimerProvider } from "react-idle-timer";
6 | import { useModal } from "@saimin/react-modal-manager";
7 | import IdleConfirmation from "@components/modals/idle-confirmation";
8 | import { useState } from "react";
9 | import useAuthOperations from "@hooks/use-auth-operations";
10 | import useAuth from "@hooks/use-auth";
11 |
12 | export function DashboardLayout() {
13 | useAuth();
14 |
15 | const { sidebarCollapsed } = useUserPreference();
16 | const { open, closeAll } = useModal();
17 | const { logout } = useAuthOperations();
18 |
19 | const [isIdle, setIsIdle] = useState(false);
20 |
21 | const handleOnIdle = () => {
22 | setIsIdle(true);
23 |
24 | if (!isIdle)
25 | open("idle", {
26 | content: ,
27 | animationType: "zoom",
28 | hideOnClickBackDrop: false,
29 | });
30 | };
31 |
32 | const handleOnActive = () => {
33 | setIsIdle(false);
34 | if (!isIdle) closeAll();
35 | };
36 |
37 | return (
38 | {
42 | if (!isIdle) handleOnActive();
43 | }}
44 | >
45 |
46 |
47 |
48 |
49 |
50 |
56 |
57 |
58 |
59 |
60 | );
61 | }
62 |
--------------------------------------------------------------------------------
/src/layouts/root/root-layout.tsx:
--------------------------------------------------------------------------------
1 | import { Outlet } from "react-router-dom";
2 |
3 | function RootLayout() {
4 | return ;
5 | }
6 |
7 | export default RootLayout;
8 |
--------------------------------------------------------------------------------
/src/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { clsx, type ClassValue } from "clsx"
2 | import { twMerge } from "tailwind-merge"
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs))
6 | }
7 |
--------------------------------------------------------------------------------
/src/main.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from "react";
2 | import { createRoot } from "react-dom/client";
3 | import App from "./App.tsx";
4 | import "./index.css";
5 | import "./i18n";
6 |
7 | createRoot(document.getElementById("root")!).render(
8 |
9 |
10 |
11 | );
12 |
--------------------------------------------------------------------------------
/src/pages/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinPyaeKyaw/shadcn-admin-starter-template/965735f31f0d52136bc1b4da672592de19175f38/src/pages/.DS_Store
--------------------------------------------------------------------------------
/src/pages/charts/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinPyaeKyaw/shadcn-admin-starter-template/965735f31f0d52136bc1b4da672592de19175f38/src/pages/charts/.DS_Store
--------------------------------------------------------------------------------
/src/pages/error-pages/404-page.tsx:
--------------------------------------------------------------------------------
1 | import { Error } from "./components/Error";
2 |
3 | export function Error404() {
4 | return (
5 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/src/pages/error-pages/500-page.tsx:
--------------------------------------------------------------------------------
1 | import { Error } from "./components/Error";
2 |
3 | export function Error500() {
4 | return (
5 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/src/pages/error-pages/components/Error.tsx:
--------------------------------------------------------------------------------
1 | import Center from "@components/commons/center";
2 | import Lottie from "lottie-react";
3 | import Text from "@components/commons/text";
4 | import cat from "@assets/lotties/cat.json";
5 |
6 | interface Props {
7 | code: string | number;
8 | description: string;
9 | }
10 |
11 | export function Error({ code, description }: Props) {
12 | return (
13 |
14 |
15 |
16 |
{code}
17 | {description}
18 |
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/src/pages/form/form-page.tsx:
--------------------------------------------------------------------------------
1 | import PageTitle from "@components/commons/page-title";
2 | import FormWithReusableInputs from "./components/FormWithReusableInputs";
3 | import { useTranslation } from "react-i18next";
4 |
5 | export function Form() {
6 | const { t } = useTranslation();
7 |
8 | return (
9 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/src/pages/form/mock-data/mock-data.ts:
--------------------------------------------------------------------------------
1 | export const radioData = [
2 | { value: "radio one", label: "Radio One" },
3 | { value: "radio two", label: "Radio Two" },
4 | { value: "radio three", label: "Radio Three" },
5 | ];
6 |
7 | export const selectData = [
8 | { value: "select one", label: "Select One" },
9 | { value: "select two", label: "Select Two" },
10 | { value: "select three", label: "Select Three" },
11 | ];
12 |
13 | export const checkgpData = [
14 | { value: "check group one", label: "Check Group One" },
15 | { value: "check group two", label: "Check Group Two" },
16 | { value: "check group three", label: "Check Group Three" },
17 | ];
18 |
--------------------------------------------------------------------------------
/src/pages/form/schemas/normal-form-schema.ts:
--------------------------------------------------------------------------------
1 | import {
2 | requiredCheckGroup,
3 | requiredString,
4 | requiredTrueValue,
5 | } from "@helpers/form-schemas-validators";
6 | import { z } from "zod";
7 |
8 | export const normalFormSchema = z.object({
9 | textInput: requiredString("This field is required!"),
10 | textInputWithDesc: requiredString("This field is required!"),
11 | selectInput: requiredString("This field is required!"),
12 | radioInput: requiredString("This field is required!"),
13 | checkgroupInput: requiredCheckGroup("This field is required!"),
14 | checkboxInput: requiredTrueValue("Need to be checked"),
15 | passwordInput: requiredString("This field is required!"),
16 | dateInput: requiredString("This field is required!"),
17 | textareaInput: requiredString("This field is required!"),
18 | });
19 |
--------------------------------------------------------------------------------
/src/pages/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./modals/modals-page";
2 | export * from "./dashboard/dashboard-page";
3 | export * from "./charts/charts-page";
4 | export * from "./table/list-page";
5 | export * from "./table/create-page";
6 | export * from "./form/form-page";
7 | export * from "./error-pages/404-page";
8 | export * from "./error-pages/500-page";
9 | export * from "./login/login-page";
10 |
--------------------------------------------------------------------------------
/src/pages/login/login-page.tsx:
--------------------------------------------------------------------------------
1 | import { Form } from "@components/ui/form";
2 | import { toast } from "sonner";
3 | import Text from "@components/commons/text";
4 | import { useForm } from "react-hook-form";
5 | import { zodResolver } from "@hookform/resolvers/zod";
6 | import { loginSchema } from "./schemas/login-schema";
7 | import TextInput from "@components/inputs/text-input";
8 | import PasswordInput from "@components/inputs/password-input";
9 | import { Button } from "@components/ui/button";
10 | import useAuthOperations from "@hooks/use-auth-operations";
11 | import { ADMIN } from "@configs/vars";
12 | import { useTranslation } from "react-i18next";
13 |
14 | type FormType = {
15 | username: string;
16 | password: string;
17 | };
18 |
19 | export function Login() {
20 | const { login } = useAuthOperations();
21 | const { t } = useTranslation();
22 | const form = useForm({
23 | resolver: zodResolver(loginSchema),
24 | defaultValues: {
25 | username: "",
26 | password: "",
27 | },
28 | });
29 |
30 | function onSubmit(values: FormType) {
31 | if (
32 | ADMIN.username === values.username &&
33 | ADMIN.password === values.password
34 | ) {
35 | login(values);
36 | } else {
37 | toast.error("Wrong username or password");
38 | }
39 | }
40 |
41 | return (
42 |
76 |
77 | );
78 | }
79 |
--------------------------------------------------------------------------------
/src/pages/login/schemas/login-schema.ts:
--------------------------------------------------------------------------------
1 | import { requiredString } from "@helpers/form-schemas-validators";
2 | import { z } from "zod";
3 |
4 | export const loginSchema = z.object({
5 | username: requiredString("Username is required!"),
6 | password: requiredString("Password is required!"),
7 | });
8 |
--------------------------------------------------------------------------------
/src/pages/modals/components/ModalCard.tsx:
--------------------------------------------------------------------------------
1 | import Text from "@components/commons/text";
2 | import { Button } from "@components/ui/button";
3 |
4 | interface Props {
5 | modal: {
6 | id: string;
7 | title: string;
8 | description: string;
9 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
10 | modalProps?: any;
11 | };
12 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
13 | open: (id: string, modalProps: any) => void;
14 | }
15 |
16 | function ModalCard({ modal, open }: Props) {
17 | return (
18 |
19 |
20 | {modal.title}
21 |
22 |
23 | {modal.description}
24 |
27 |
28 | );
29 | }
30 |
31 | export default ModalCard;
32 |
--------------------------------------------------------------------------------
/src/pages/modals/components/ToastCard.tsx:
--------------------------------------------------------------------------------
1 | import Text from "@components/commons/text";
2 | import { Button } from "@components/ui/button";
3 |
4 | interface Props {
5 | toast: {
6 | id: string;
7 | title: string;
8 | description: string;
9 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
10 | toastProps?: any;
11 | };
12 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
13 | open: (toastProps: any) => void;
14 | }
15 |
16 | function ToastCard({ toast, open }: Props) {
17 | return (
18 |
19 |
20 | {toast.title}
21 |
22 |
23 | {toast.description}
24 |
25 |
26 | );
27 | }
28 |
29 | export default ToastCard;
30 |
--------------------------------------------------------------------------------
/src/pages/modals/mock-data/modals.ts:
--------------------------------------------------------------------------------
1 | const modals = [
2 | {
3 | id: "default",
4 | title: "Default Modal",
5 | description:
6 | "This is a standard modal without any special animations or customizations.",
7 | },
8 | {
9 | id: "zoom",
10 | title: "Modal with zoom animation",
11 | description:
12 | "This modal opens with a zoom effect, making the modal content appear as if it's zooming in.",
13 | modalProps: {
14 | animationType: "zoom",
15 | },
16 | },
17 | {
18 | id: "fade",
19 | title: "Modal with fade animation",
20 | description:
21 | "This modal uses a fade animation, making the modal content gradually appear or disappear.",
22 | modalProps: {
23 | animationType: "fade",
24 | },
25 | },
26 | {
27 | id: "slide-top",
28 | title: "Modal with slide from top animation",
29 | description:
30 | "This modal slides down from the top of the screen when opening and back up when closing.",
31 | modalProps: {
32 | animationType: "slide-from-top",
33 | },
34 | },
35 | {
36 | id: "slide-down",
37 | title: "Modal with slide from bottom animation",
38 | description:
39 | "This modal slides up from the bottom of the screen when opening and back down when closing.",
40 | modalProps: {
41 | animationType: "slide-from-bottom",
42 | },
43 | },
44 | {
45 | id: "backdrop-opacity",
46 | title: "Modal with customized backdrop",
47 | description:
48 | "This modal has a custom backdrop with 80% opacity and a pink background, combined with a zoom animation.",
49 | modalProps: {
50 | backdropOpacity: 0.8,
51 | backdropColor: "pink",
52 | animationType: "zoom",
53 | },
54 | },
55 | ];
56 |
57 | export default modals;
58 |
--------------------------------------------------------------------------------
/src/pages/modals/mock-data/toasts.ts:
--------------------------------------------------------------------------------
1 | const toasts = [
2 | {
3 | id: "default",
4 | title: "Default Toast",
5 | description:
6 | "A basic toast notification with a message to inform users about the status of their request.",
7 | toastProps: {
8 | description: "There was a problem with your request.",
9 | },
10 | },
11 | {
12 | id: "title",
13 | title: "Toast with Title",
14 | description:
15 | "A toast notification with a bold title, offering more emphasis on the alert message.",
16 | toastProps: {
17 | title: "Uh oh! Something went wrong.",
18 | description: "There was a problem with your request.",
19 | },
20 | },
21 | {
22 | id: "action",
23 | title: "Toast with Action",
24 | description:
25 | "A toast notification that includes an action button, allowing users to take immediate action on the alert.",
26 | toastProps: {
27 | title: "Uh oh! Something went wrong.",
28 | description: "There was a problem with your request.",
29 | action: true,
30 | },
31 | },
32 | {
33 | id: "error",
34 | title: "Error Toast",
35 | description:
36 | "A destructive variant of the toast, signaling an error or critical issue that requires attention.",
37 | toastProps: {
38 | variant: "destructive",
39 | title: "Uh oh! Something went wrong.",
40 | description: "There was a problem with your request.",
41 | },
42 | },
43 | ];
44 |
45 | export default toasts;
46 |
--------------------------------------------------------------------------------
/src/pages/modals/modals-page.tsx:
--------------------------------------------------------------------------------
1 | import { useModal } from "@saimin/react-modal-manager";
2 | import ModalCard from "./components/ModalCard";
3 | import DemoModal from "@components/modals/demo";
4 | import PageTitle from "@components/commons/page-title";
5 | import modals from "./mock-data/modals";
6 | import { useTranslation } from "react-i18next";
7 |
8 | export function Modals() {
9 | const { t } = useTranslation();
10 | const { open } = useModal();
11 |
12 | const handleOpenModal = (id: string, modalProps: any): void => {
13 | open(id, {
14 | content: ,
15 | ...modalProps,
16 | });
17 | };
18 |
19 | return (
20 |
21 |
22 |
23 |
24 | {modals.map((m) => (
25 |
26 | ))}
27 |
28 |
29 |
30 | );
31 | }
32 |
--------------------------------------------------------------------------------
/src/pages/table/components/columns.tsx:
--------------------------------------------------------------------------------
1 | import { Checkbox } from "@components/ui/checkbox";
2 | import { DataTableColumnHeader } from "@components/data-table/data-table-column-header";
3 | import { RowActions } from "./row-actions";
4 |
5 | export const columns: any = [
6 | {
7 | id: "select",
8 | header: ({ table }: any) => (
9 | table.toggleAllPageRowsSelected(!!value)}
15 | aria-label="Select all"
16 | className="translate-y-[2px]"
17 | />
18 | ),
19 | cell: ({ row }: any) => (
20 | row.toggleSelected(!!value)}
23 | aria-label="Select row"
24 | className="translate-y-[2px]"
25 | />
26 | ),
27 | enableSorting: false,
28 | },
29 | {
30 | accessorKey: "id",
31 | header: ({ column }: any) => (
32 |
33 | ),
34 | cell: ({ row }: any) => {row.getValue("id")}
,
35 | enableSorting: false,
36 | },
37 | {
38 | accessorKey: "title",
39 | header: ({ column }: any) => (
40 |
41 | ),
42 | cell: ({ row }: any) => {
43 | return {row.getValue("title")}
;
44 | },
45 | },
46 | {
47 | accessorKey: "brand",
48 | header: ({ column }: any) => (
49 |
50 | ),
51 | cell: ({ row }: any) => {
52 | return {row.getValue("brand")}
;
53 | },
54 | filterFn: (row: any, id: any, value: any) => {
55 | return value.includes(row.getValue(id));
56 | },
57 | },
58 | {
59 | accessorKey: "availabilityStatus",
60 | header: ({ column }: any) => (
61 |
62 | ),
63 | cell: ({ row }: any) => {
64 | return {row.getValue("availabilityStatus")}
;
65 | },
66 | filterFn: (row: any, id: any, value: any) => {
67 | return value.includes(row.getValue(id));
68 | },
69 | },
70 | {
71 | id: "actions",
72 | cell: () => ,
73 | },
74 | ];
75 |
--------------------------------------------------------------------------------
/src/pages/table/components/row-actions.tsx:
--------------------------------------------------------------------------------
1 | import { DotsHorizontalIcon } from "@radix-ui/react-icons";
2 |
3 | import { Button } from "@components/ui/button";
4 | import {
5 | DropdownMenu,
6 | DropdownMenuContent,
7 | DropdownMenuItem,
8 | DropdownMenuSeparator,
9 | DropdownMenuShortcut,
10 | DropdownMenuTrigger,
11 | } from "@components/ui/dropdown-menu";
12 |
13 | export function RowActions() {
14 | return (
15 |
16 |
17 |
24 |
25 |
26 | Edit
27 | Make a copy
28 | Favorite
29 |
30 |
31 |
32 | Delete
33 | ⌘⌫
34 |
35 |
36 |
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/src/pages/table/list-page.tsx:
--------------------------------------------------------------------------------
1 | import { DataTable } from "@components/data-table/data-table";
2 | import { columns } from "./components/columns";
3 | import PageTitle from "@components/commons/page-title";
4 | import { useState } from "react";
5 | import { useGetAllProducts } from "@apis/queries/product";
6 | import { PaginationState } from "@tanstack/react-table";
7 | import Toolbar from "./components/tool-bar";
8 | import { useForm } from "react-hook-form";
9 | import { useTranslation } from "react-i18next";
10 |
11 | type FormType = {
12 | category: string;
13 | search: string;
14 | };
15 |
16 | export function TableList() {
17 | const { t } = useTranslation();
18 |
19 | const toolbarForm = useForm({
20 | defaultValues: {
21 | category: "",
22 | search: "",
23 | },
24 | });
25 |
26 | const [paginationState, setPaginationState] = useState({
27 | pageIndex: 0,
28 | pageSize: 10,
29 | });
30 |
31 | const { data, isLoading } = useGetAllProducts({
32 | skip: paginationState.pageIndex * paginationState.pageSize,
33 | limit: paginationState.pageSize,
34 | ...toolbarForm.watch(),
35 | });
36 |
37 | return (
38 |
39 |
40 |
41 |
42 |
43 |
52 |
53 | );
54 | }
55 |
--------------------------------------------------------------------------------
/src/pages/table/mock-data/mock-data.ts:
--------------------------------------------------------------------------------
1 | export const radioData = [
2 | { value: "radio one", label: "Radio One" },
3 | { value: "radio two", label: "Radio Two" },
4 | { value: "radio three", label: "Radio Three" },
5 | ];
6 |
7 | export const selectData = [
8 | { value: "select one", label: "Select One" },
9 | { value: "select two", label: "Select Two" },
10 | { value: "select three", label: "Select Three" },
11 | ];
12 |
13 | export const checkgpData = [
14 | { value: "check group one", label: "Check Group One" },
15 | { value: "check group two", label: "Check Group Two" },
16 | { value: "check group three", label: "Check Group Three" },
17 | ];
18 |
--------------------------------------------------------------------------------
/src/pages/table/schemas/normal-form-schema.ts:
--------------------------------------------------------------------------------
1 | import {
2 | requiredCheckGroup,
3 | requiredString,
4 | requiredTrueValue,
5 | } from "@helpers/form-schemas-validators";
6 | import { z } from "zod";
7 |
8 | export const normalFormSchema = z.object({
9 | textInput: requiredString("This field is required!"),
10 | textInputWithDesc: requiredString("This field is required!"),
11 | selectInput: requiredString("This field is required!"),
12 | radioInput: requiredString("This field is required!"),
13 | checkgroupInput: requiredCheckGroup("This field is required!"),
14 | checkboxInput: requiredTrueValue("Need to be checked"),
15 | passwordInput: requiredString("This field is required!"),
16 | dateInput: requiredString("This field is required!"),
17 | textareaInput: requiredString("This field is required!"),
18 | });
19 |
--------------------------------------------------------------------------------
/src/stores/user-preference.ts:
--------------------------------------------------------------------------------
1 | import { create } from "zustand";
2 | import { createJSONStorage, devtools, persist } from "zustand/middleware";
3 |
4 | interface State {
5 | sidebarCollapsed: boolean;
6 | lang: Lang;
7 | changeLang: (lang: Lang) => void;
8 | toggleSidebar: () => void;
9 | }
10 |
11 | const useUserPreference = create()(
12 | devtools(
13 | persist(
14 | (set) => ({
15 | lang: "en",
16 | sidebarCollapsed: false,
17 | changeLang: (lang: Lang) => set((state) => ({ ...state, lang })),
18 | toggleSidebar: () =>
19 | set((state) => ({
20 | ...state,
21 | sidebarCollapsed: !state.sidebarCollapsed,
22 | })),
23 | }),
24 | {
25 | name: "user-preference",
26 | storage: createJSONStorage(() => localStorage),
27 | }
28 | )
29 | )
30 | );
31 |
32 | export default useUserPreference;
33 |
--------------------------------------------------------------------------------
/src/types/global.d.ts:
--------------------------------------------------------------------------------
1 | declare global {
2 | type Lang = "en" | "mm";
3 |
4 | type Theme = "dark" | "light";
5 |
6 | type DataType = { value: string | Record; label: string };
7 | }
8 |
9 | export {};
10 |
--------------------------------------------------------------------------------
/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | darkMode: ["class"],
4 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
5 |
6 | theme: {
7 | extend: {
8 | borderRadius: {
9 | lg: "var(--radius)",
10 | md: "calc(var(--radius) - 2px)",
11 | sm: "calc(var(--radius) - 4px)",
12 | },
13 | colors: {
14 | background: "hsl(var(--background))",
15 | foreground: "hsl(var(--foreground))",
16 | card: {
17 | DEFAULT: "hsl(var(--card))",
18 | foreground: "hsl(var(--card-foreground))",
19 | },
20 | popover: {
21 | DEFAULT: "hsl(var(--popover))",
22 | foreground: "hsl(var(--popover-foreground))",
23 | },
24 | primary: {
25 | DEFAULT: "hsl(var(--primary))",
26 | foreground: "hsl(var(--primary-foreground))",
27 | },
28 | secondary: {
29 | DEFAULT: "hsl(var(--secondary))",
30 | foreground: "hsl(var(--secondary-foreground))",
31 | },
32 | muted: {
33 | DEFAULT: "hsl(var(--muted))",
34 | foreground: "hsl(var(--muted-foreground))",
35 | },
36 | accent: {
37 | DEFAULT: "hsl(var(--accent))",
38 | foreground: "hsl(var(--accent-foreground))",
39 | },
40 | destructive: {
41 | DEFAULT: "hsl(var(--destructive))",
42 | foreground: "hsl(var(--destructive-foreground))",
43 | },
44 | border: "hsl(var(--border))",
45 | input: "hsl(var(--input))",
46 | ring: "hsl(var(--ring))",
47 | chart: {
48 | 1: "hsl(var(--chart-1))",
49 | 2: "hsl(var(--chart-2))",
50 | 3: "hsl(var(--chart-3))",
51 | 4: "hsl(var(--chart-4))",
52 | 5: "hsl(var(--chart-5))",
53 | },
54 | },
55 | },
56 | },
57 | plugins: [require("tailwindcss-animate")],
58 | };
59 |
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "isolatedModules": true,
13 | "moduleDetection": "force",
14 | "noEmit": true,
15 | "jsx": "react-jsx",
16 |
17 | /* Linting */
18 | "strict": true,
19 | "noUnusedLocals": true,
20 | "noUnusedParameters": true,
21 | "noFallthroughCasesInSwitch": true,
22 |
23 | "baseUrl": ".",
24 | "paths": {
25 | "@assets/*": ["./src/assets/*"],
26 | "@layouts/*": ["./src/layouts/*"],
27 | "@components/*": ["./src/components/*"],
28 | "@configs/*": ["./src/configs/*"],
29 | "@hooks/*": ["./src/hooks/*"],
30 | "@lib/*": ["./src/lib/*"],
31 | "@pages/*": ["./src/pages/*"],
32 | "@stores/*": ["./src/stores/*"],
33 | "@helpers/*": ["./src/helpers/*"],
34 | "@apis/*": ["./src/apis/*"]
35 | }
36 | },
37 | "include": ["src"]
38 | }
39 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": [],
3 | "references": [
4 | { "path": "./tsconfig.app.json" },
5 | { "path": "./tsconfig.node.json" }
6 | ],
7 | "compilerOptions": {
8 | "baseUrl": ".",
9 | "paths": {
10 | "@assets/*": ["./src/assets/*"],
11 | "@layouts/*": ["./src/layouts/*"],
12 | "@components/*": ["./src/components/*"],
13 | "@configs/*": ["./src/configs/*"],
14 | "@hooks/*": ["./src/hooks/*"],
15 | "@lib/*": ["./src/lib/*"],
16 | "@pages/*": ["./src/pages/*"],
17 | "@stores/*": ["./src/stores/*"],
18 | "@helpers/*": ["./src/helpers/*"],
19 | "@apis/*": ["./src/apis/*"]
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2022",
4 | "lib": ["ES2023"],
5 | "module": "ESNext",
6 | "skipLibCheck": true,
7 |
8 | /* Bundler mode */
9 | "moduleResolution": "bundler",
10 | "allowImportingTsExtensions": true,
11 | "isolatedModules": true,
12 | "moduleDetection": "force",
13 | "noEmit": true,
14 |
15 | /* Linting */
16 | "strict": true,
17 | "noUnusedLocals": true,
18 | "noUnusedParameters": true,
19 | "noFallthroughCasesInSwitch": true
20 | },
21 | "include": ["vite.config.ts"]
22 | }
23 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import path from "path";
2 | import react from "@vitejs/plugin-react";
3 | import { defineConfig } from "vite";
4 |
5 | export default defineConfig({
6 | plugins: [react()],
7 | resolve: {
8 | alias: {
9 | "@assets": path.resolve(__dirname, "./src/assets"),
10 | "@layouts": path.resolve(__dirname, "./src/layouts"),
11 | "@components": path.resolve(__dirname, "./src/components"),
12 | "@configs": path.resolve(__dirname, "./src/configs"),
13 | "@lib": path.resolve(__dirname, "./src/lib"),
14 | "@hooks": path.resolve(__dirname, "./src/hooks"),
15 | "@pages": path.resolve(__dirname, "./src/pages"),
16 | "@stores": path.resolve(__dirname, "./src/stores"),
17 | "@helpers": path.resolve(__dirname, "./src/helpers"),
18 | "@apis": path.resolve(__dirname, "./src/apis"),
19 | },
20 | },
21 | });
22 |
--------------------------------------------------------------------------------