revamp template

This commit is contained in:
fro1991
2025-02-01 16:44:51 +07:00
parent c432df568a
commit 276a289580
1212 changed files with 112762 additions and 0 deletions

View File

@ -0,0 +1,55 @@
import { toAbsoluteUrl } from '@/utils';
import { Link } from 'react-router-dom';
import {
Dialog,
DialogBody,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle
} from '@/components/ui/dialog';
interface IModalAccountDeactivatedProps {
open: boolean;
onOpenChange: () => void;
}
const ModalAccountDeactivated = ({ open, onOpenChange }: IModalAccountDeactivatedProps) => {
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="w-full max-w-[500px] max-h-[95%] scrollable-y-auto">
<DialogHeader className="justify-end border-0 pt-5">
<DialogTitle></DialogTitle>
<DialogDescription></DialogDescription>
</DialogHeader>
<DialogBody className="flex flex-col items-center pt-0 pb-10">
<div className="mb-9">
<img
src={toAbsoluteUrl('/media/illustrations/23.svg')}
className="dark:hidden max-h-[150px]"
/>
<img
src={toAbsoluteUrl('/media/illustrations/23-dark.svg')}
className="light:hidden max-h-[150px]"
/>
</div>
<h3 className="text-lg font-medium text-gray-900 text-center mb-3">
Account Deactivated
</h3>
<div className="text-2sm text-center text-gray-700 mb-7">
Your account has been deactivated. Please contact <br />
support if this is an error or for reactivation.
</div>
<Link to="/" className="btn btn-primary flex justify-center">
Go to Home
</Link>
</DialogBody>
</DialogContent>
</Dialog>
);
};
export { ModalAccountDeactivated };

View File

@ -0,0 +1 @@
export * from './ModalAccountDeactivated';

View File

@ -0,0 +1,49 @@
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle
} from '@/components/ui/dialog';
import {
ModalShareProfileViaLink,
ModalShareProfileViaEmail,
ModalShareProfileUsers,
ModalShareProfileSettings
} from '@/partials/modals/share-profile';
interface ModalGiveAwardProps {
open: boolean;
onOpenChange: () => void;
}
const ModalGiveAward = ({ open, onOpenChange }: ModalGiveAwardProps) => {
const scrollableHeight = 300;
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-[600px]">
<DialogHeader className="py-4 px-5">
<DialogTitle>Give Award</DialogTitle>
<DialogDescription></DialogDescription>
</DialogHeader>
<div className="grid gap-5 px-0 py-5">
<ModalShareProfileViaLink />
<div className="border-b border-b-gray-200"></div>
<ModalShareProfileViaEmail />
<div className="border-b border-b-gray-200"></div>
<div className="scrollable-y-auto" style={{ maxHeight: `${scrollableHeight}px` }}>
<ModalShareProfileUsers />
</div>
<div className="border-b border-b-gray-200"></div>
<ModalShareProfileSettings />
</div>
</DialogContent>
</Dialog>
);
};
export { ModalGiveAward };

View File

@ -0,0 +1,6 @@
export * from './ModalGiveAward';
export * from '@/partials/modals/share-profile/ModalShareProfileViaLink';
export * from '@/partials/modals/share-profile/ModalShareProfileViaEmail';
export * from '@/partials/modals/share-profile/ModalShareProfileUsers';
export * from '@/partials/modals/share-profile/ModalShareProfileSettings';
export * from './types';

View File

@ -0,0 +1,5 @@
export interface IModalGiveAwardDocsItem {
image: string;
desc: string;
date: string;
}

View File

@ -0,0 +1,136 @@
import React, { forwardRef } from 'react';
import { toAbsoluteUrl } from '@/utils';
import { Link } from 'react-router-dom';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle
} from '@/components/ui/dialog';
interface IModalReportUserProps {
open: boolean;
onOpenChange: () => void;
}
const ModalReportUser = forwardRef<HTMLDivElement, IModalReportUserProps>(
({ open, onOpenChange }, ref) => {
const buildNotice = () => {
return (
<div className="grid place-items-center gap-1 px-5">
<div className="flex justify-center items-center rounded-full">
<img
src={toAbsoluteUrl('/media/avatars/300-1.png')}
className="rounded-full max-h-[55px] max-w-full"
alt=""
/>
</div>
<div className="flex items-center justify-center gap-1">
<Link
to="#"
className="hover:text-primary-active text-2sm leading-5 font-semibold text-gray-900"
>
Jenny Klabber
</Link>
<svg
xmlns="http://www.w3.org/2000/svg"
width="13"
height="13"
viewBox="0 0 15 16"
fill="none"
className="text-primary"
>
<path
d="M14.5425 6.89749L13.5 5.83999C13.4273 5.76877 13.3699 5.6835 13.3312 5.58937C13.2925 5.49525 13.2734 5.39424 13.275 5.29249V3.79249C13.274 3.58699 13.2324 3.38371 13.1527 3.19432C13.0729 3.00494 12.9565 2.83318 12.8101 2.68892C12.6638 2.54466 12.4904 2.43073 12.2998 2.35369C12.1093 2.27665 11.9055 2.23801 11.7 2.23999H10.2C10.0982 2.24159 9.99722 2.22247 9.9031 2.18378C9.80898 2.1451 9.72371 2.08767 9.65249 2.01499L8.60249 0.957487C8.30998 0.665289 7.91344 0.50116 7.49999 0.50116C7.08654 0.50116 6.68999 0.665289 6.39749 0.957487L5.33999 1.99999C5.26876 2.07267 5.1835 2.1301 5.08937 2.16879C4.99525 2.20747 4.89424 2.22659 4.79249 2.22499H3.29249C3.08699 2.22597 2.88371 2.26754 2.69432 2.34731C2.50494 2.42709 2.33318 2.54349 2.18892 2.68985C2.04466 2.8362 1.93073 3.00961 1.85369 3.20013C1.77665 3.39064 1.73801 3.5945 1.73999 3.79999V5.29999C1.74159 5.40174 1.72247 5.50275 1.68378 5.59687C1.6451 5.691 1.58767 5.77627 1.51499 5.84749L0.457487 6.89749C0.165289 7.19 0.00115967 7.58654 0.00115967 7.99999C0.00115967 8.41344 0.165289 8.80998 0.457487 9.10249L1.49999 10.16C1.57267 10.2312 1.6301 10.3165 1.66878 10.4106C1.70747 10.5047 1.72659 10.6057 1.72499 10.7075V12.2075C1.72597 12.413 1.76754 12.6163 1.84731 12.8056C1.92709 12.995 2.04349 13.1668 2.18985 13.3111C2.3362 13.4553 2.50961 13.5692 2.70013 13.6463C2.89064 13.7233 3.0945 13.762 3.29999 13.76H4.79999C4.90174 13.7584 5.00275 13.7775 5.09687 13.8162C5.191 13.8549 5.27627 13.9123 5.34749 13.985L6.40499 15.0425C6.69749 15.3347 7.09404 15.4988 7.50749 15.4988C7.92094 15.4988 8.31748 15.3347 8.60999 15.0425L9.65999 14C9.73121 13.9273 9.81647 13.8699 9.9106 13.8312C10.0047 13.7925 10.1057 13.7734 10.2075 13.775H11.7075C12.1212 13.775 12.518 13.6106 12.8106 13.3181C13.1031 13.0255 13.2675 12.6287 13.2675 12.215V10.715C13.2659 10.6132 13.285 10.5122 13.3237 10.4181C13.3624 10.324 13.4198 10.2387 13.4925 10.1675L14.55 9.10999C14.6953 8.96452 14.8104 8.79176 14.8887 8.60164C14.9671 8.41152 15.007 8.20779 15.0063 8.00218C15.0056 7.79656 14.9643 7.59311 14.8847 7.40353C14.8051 7.21394 14.6888 7.04197 14.5425 6.89749ZM10.635 6.64999L6.95249 10.25C6.90055 10.3026 6.83864 10.3443 6.77038 10.3726C6.70212 10.4009 6.62889 10.4153 6.55499 10.415C6.48062 10.4139 6.40719 10.3982 6.33896 10.3685C6.27073 10.3389 6.20905 10.2961 6.15749 10.2425L4.37999 8.44249C4.32532 8.39044 4.28169 8.32793 4.25169 8.25867C4.22169 8.18941 4.20593 8.11482 4.20536 8.03934C4.20479 7.96387 4.21941 7.88905 4.24836 7.81934C4.27731 7.74964 4.31999 7.68647 4.37387 7.63361C4.42774 7.58074 4.4917 7.53926 4.56194 7.51163C4.63218 7.484 4.70726 7.47079 4.78271 7.47278C4.85816 7.47478 4.93244 7.49194 5.00112 7.52324C5.0698 7.55454 5.13148 7.59935 5.18249 7.65499L6.56249 9.05749L9.84749 5.84749C9.95296 5.74215 10.0959 5.68298 10.245 5.68298C10.394 5.68298 10.537 5.74215 10.6425 5.84749C10.6953 5.90034 10.737 5.96318 10.7653 6.03234C10.7935 6.1015 10.8077 6.1756 10.807 6.25031C10.8063 6.32502 10.7908 6.39884 10.7612 6.46746C10.7317 6.53608 10.6888 6.59813 10.635 6.64999Z"
fill="currentColor"
/>
</svg>
</div>
</div>
);
};
const buildOptions = () => {
const items = [
{
name: 'Impersonation',
description: 'It looks like this profile might be impersonating someone else'
},
{
name: 'Off bumble behavior',
description: 'This person has engaged in behavior that is abusive, bullying'
},
{
name: 'Something else',
description: 'None of the reasons listed above are suitable'
}
];
return (
<div className="flex flex-col gap-5 px-5">
<div className="text-2sm text-gray-900 font-semibold">
Let us know why youre reporing this person
</div>
<div className="flex flex-col gap-3.5">
{items.map((item, index) => (
<label key={index} className="form-label flex items-center gap-2.5">
<input
className="radio radio-sm"
name="report-option"
type="radio"
value="{{ loop.index }}"
/>
<div className="flex flex-col gap-0.5">
<div className="text-sm font-semibold text-gray-900">{item.name}</div>
<div className="text-2sm font-medium text-gray-600">{item.description}</div>
</div>
</label>
))}
</div>
</div>
);
};
const buildFooter = () => {
return (
<div className="text-2sm font-medium text-center text-gray-800 p-x">
Don't worry, your report is completely anonymous; the person you're <br />
reporting will not be informed that you've submitted it
</div>
);
};
const buildButton = () => {
return (
<div className="flex items-center gap-2.5 justify-end px-5">
<button className="btn btn-sm btn-primary">Report this person</button>
<button className="btn btn-sm btn-light">Cancel</button>
</div>
);
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-[600px]" ref={ref}>
<DialogHeader>
<DialogTitle>Report User</DialogTitle>
<DialogDescription></DialogDescription>
</DialogHeader>
<div className="grid gap-5 px-0 py-5">
{buildNotice()}
<div className="border-b border-b-gray-200"></div>
{buildOptions()}
<div className="border-b border-b-gray-200"></div>
{buildFooter()}
<div className="border-b border-b-gray-200"></div>
{buildButton()}
</div>
</DialogContent>
</Dialog>
);
}
);
export { ModalReportUser };

View File

@ -0,0 +1 @@
export * from './ModalReportUser';

View File

@ -0,0 +1,321 @@
import React, { ChangeEvent, forwardRef, useEffect, useState } from 'react';
import { KeenIcon, Menu, MenuItem, MenuToggle } from '@/components';
import { Tab, TabPanel, Tabs, TabsList } from '@/components/tabs';
import { DropdownCrud2 } from '@/partials/dropdowns/general';
import { useViewport } from '@/hooks';
import { useLanguage } from '@/i18n';
import {
ModalSearchDocs,
ModalSearchMixed,
ModalSearchSettings,
ModalSearchIntegrations,
ModalSearchUsers,
ModalSearchEmpty,
ModalSearchNoResults,
IModalSearchDocsItem,
IModalSearchUsersItem,
IModalSearchSettingsItem,
IModalSearchIntegrationsItem
} from './';
import {
Dialog,
DialogBody,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle
} from '@/components/ui/dialog';
interface IModalSearchProps {
open: boolean;
onOpenChange: () => void;
}
const ModalSearch = forwardRef<HTMLDivElement, IModalSearchProps>(({ open, onOpenChange }, ref) => {
const [scrollableHeight, setScrollableHeight] = useState<number>(0);
const [viewportHeight] = useViewport();
const { isRTL } = useLanguage();
const offset = 300;
const [searchInput, setSearchInput] = useState('');
useEffect(() => {
setScrollableHeight(viewportHeight - offset);
}, [viewportHeight]);
const mixedSettingsItems: IModalSearchSettingsItem[] = [
{ icon: 'badge', info: 'Public Profile' },
{ icon: 'setting-2', info: 'My Account' },
{ icon: 'message-programming', info: 'Devs Forum' }
];
const mixedUsersItems: IModalSearchUsersItem[] = [
{
avatar: '300-3.png',
name: 'Tyler Hero',
email: 'tyler.hero@gmail.com',
label: 'In Office',
color: 'badge-success'
},
{
avatar: '300-1.png',
name: 'Esther Howard',
email: 'esther.howard@gmail.com',
label: 'On Leave',
color: 'badge-danger'
}
];
const mixedIntegrationsItems: IModalSearchIntegrationsItem[] = [
{
logo: 'jira.svg',
name: 'Jira',
description: 'Project management',
team: [
{ filename: '300-4.png', variant: 'size-6' },
{ filename: '300-1.png', variant: 'size-6' },
{ filename: '300-2.png', variant: 'size-6' },
{ fallback: '+3', variant: 'text-success-inverse size-6 ring-success-light bg-success' }
]
},
{
logo: 'inferno.svg',
name: 'Inferno',
description: 'Real-time photo sharing app',
team: [
{ filename: '300-14.png', variant: 'size-6' },
{ filename: '300-12.png', variant: 'size-6' },
{ filename: '300-9.png', variant: 'size-6' }
]
}
];
const docsItems: IModalSearchDocsItem[] = [
{
image: 'pdf.svg',
desc: 'Project-pitch.pdf',
date: '4.7 MB 26 Sep 2024 3:20 PM'
},
{
image: 'doc.svg',
desc: 'Report-v1.docx',
date: '2.3 MB 1 Oct 2024 12:00 PM'
},
{
image: 'javascript.svg',
desc: 'Framework-App.js',
date: '0.8 MB 17 Oct 2024 6:46 PM'
},
{
image: 'ai.svg',
desc: 'Framework-App.js',
date: '0.8 MB 17 Oct 2024 6:46 PM'
},
{
image: 'php.svg',
desc: 'appController.js',
date: '0.1 MB 21 Nov 2024 3:20 PM'
}
];
const settingsItems = [
{
title: 'Shortcuts',
children: [
{ icon: 'home-2', info: 'Go to Dashboard' },
{ icon: 'badge', info: 'Public Profile' },
{ icon: 'profile-circle', info: 'My Profile' },
{ icon: 'setting-2', info: 'My Account' },
{ icon: 'message-programming', info: 'Devs Forum' }
]
},
{
title: 'Actions',
children: [
{ icon: 'user', info: 'Create User' },
{ icon: 'user-edit', info: 'Create Team' },
{ icon: 'subtitle', info: 'Change Plan' },
{ icon: 'setting', info: 'Setup Branding' }
]
}
];
const integrationsItems = [
{
logo: 'jira.svg',
name: 'Jira',
description: 'Project management',
team: [
{ filename: '300-4.png', variant: 'size-6' },
{ filename: '300-1.png', variant: 'size-6' },
{ filename: '300-2.png', variant: 'size-6' },
{ fallback: '+3', variant: 'text-success-inverse size-6 ring-success-light bg-success' }
]
},
{
logo: 'inferno.svg',
name: 'Inferno',
description: 'Real-time photo sharing app',
team: [
{ filename: '300-14.png', variant: 'size-6' },
{ filename: '300-12.png', variant: 'size-6' },
{ filename: '300-9.png', variant: 'size-6' }
]
},
{
logo: 'evernote.svg',
name: 'Evernote',
description: 'Notes management app',
team: [
{ filename: '300-6.png', variant: 'size-6' },
{ filename: '300-3.png', variant: 'size-6' },
{ filename: '300-1.png', variant: 'size-6' },
{ filename: '300-8.png', variant: 'size-6' }
]
},
{
logo: 'gitlab.svg',
name: 'Gitlab',
description: 'Version control and CI/CD platform',
team: [
{ filename: '300-18.png', variant: 'size-6' },
{ filename: '300-17.png', variant: 'size-6' }
]
},
{
logo: 'google-webdev.svg',
name: 'Google Webdev',
description: 'Building web experiences',
team: [
{ filename: '300-14.png', variant: 'size-6' },
{ filename: '300-20.png', variant: 'size-6' },
{ filename: '300-21.png', variant: 'size-6' }
]
}
];
const usersItems = [
{
avatar: '300-3.png',
name: 'Tyler Hero',
email: 'tyler.hero@gmail.com',
label: 'In Office',
color: 'badge-success'
},
{
avatar: '300-1.png',
name: 'Esther Howard',
email: 'esther.howard@gmail.com',
label: 'On Leave',
color: 'badge-danger'
},
{
avatar: '300-11.png',
name: 'Jacob Jones',
email: 'jacob.jones@gmail.com',
label: 'Remote',
color: 'badge-primary'
},
{
avatar: '300-5.png',
name: 'Leslie Alexander',
email: 'leslie.alexander@gmail.com',
label: 'In Office',
color: 'badge-success'
},
{
avatar: '300-2.png',
name: 'Cody Fisher',
email: 'cody.fisher@gmail.com',
label: 'Remote',
color: 'badge-primary'
}
];
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent
className="max-w-[600px] top-[5%] lg:top-[15%] translate-y-0 [&>button]:top-8 [&>button]:end-7"
ref={ref}
>
<DialogHeader className="py-4">
<DialogTitle></DialogTitle>
<DialogDescription></DialogDescription>
<KeenIcon icon="magnifier" className="text-gray-700 text-xl" />
<input
type="text"
name="query"
value={searchInput}
className="input px-0 border-none bg-transparent shadow-none ms-2.5"
onChange={(e) => setSearchInput(e.target.value)}
placeholder="Tap to start search"
/>
</DialogHeader>
<DialogBody className="p-0 pb-5">
<Tabs defaultValue={1} className="">
<TabsList className="justify-between px-5 mb-2.5">
<div className="flex items-center gap-5">
<Tab value={1}>Mixed</Tab>
<Tab value={2}>Settings</Tab>
<Tab value={3}>Integrations</Tab>
<Tab value={4}>Users</Tab>
<Tab value={5}>Docs</Tab>
<Tab value={6}>Empty</Tab>
<Tab value={7}>No Results</Tab>
</div>
<Menu className="items-stretch">
<MenuItem
toggle="dropdown"
trigger="click"
dropdownProps={{
placement: isRTL() ? 'bottom-start' : 'bottom-end',
modifiers: [
{
name: 'offset',
options: {
offset: [0, 0] // [skid, distance]
}
}
]
}}
>
<MenuToggle className="btn btn-sm btn-icon btn-light btn-clear">
<KeenIcon icon="setting-2" />
</MenuToggle>
{DropdownCrud2()}
</MenuItem>
</Menu>
</TabsList>
<div className="scrollable-y-auto" style={{ maxHeight: `${scrollableHeight}px` }}>
<TabPanel value={1}>
<ModalSearchMixed
settings={mixedSettingsItems}
integrations={mixedIntegrationsItems}
users={mixedUsersItems}
/>
</TabPanel>
<TabPanel value={2}>
<ModalSearchSettings items={settingsItems} />
</TabPanel>
<TabPanel value={3}>
<ModalSearchIntegrations items={integrationsItems} />
</TabPanel>
<TabPanel value={4}>
<ModalSearchUsers items={usersItems} />
</TabPanel>
<TabPanel value={5}>
<ModalSearchDocs items={docsItems} />
</TabPanel>
<TabPanel value={6}>
<ModalSearchEmpty />
</TabPanel>
<TabPanel value={7}>
<ModalSearchNoResults />
</TabPanel>
</div>
</Tabs>
</DialogBody>
</DialogContent>
</Dialog>
);
});
export { ModalSearch };

View File

@ -0,0 +1,45 @@
import { KeenIcon } from '@/components';
import { toAbsoluteUrl } from '@/utils';
import React from 'react';
import { IModalSearchDocsItem } from './types';
// Define the interface for the items
interface IModalSearchDocsProps {
items: IModalSearchDocsItem[];
}
const ModalSearchDocs = ({ items }: IModalSearchDocsProps) => {
// Example items moved inside the component
return (
<div className="menu menu-default p-0 flex-col">
<div className="grid">
{items.map((item, index) => (
<div className="menu-item" key={index}>
<div className="menu-link flex items-center">
<div className="flex items-center grow gap-2.5">
<img src={toAbsoluteUrl(`/media/file-types/${item.image}`)} alt={item.desc} />
<div className="flex flex-col">
<span className="text-sm font-semibold text-gray-900 cursor-pointer hover:text-primary mb-px">
{item.desc}
</span>
<span className="text-xs font-medium text-gray-500">{item.date}</span>
</div>
</div>
<button className="btn btn-icon btn-light btn-clear btn-sm">
<KeenIcon icon="dots-vertical" />
</button>
</div>
</div>
))}
<div className="menu-item px-4 pt-2.5">
<a href="#" className="btn btn-sm btn-light justify-center">
Go to Users
</a>
</div>
</div>
</div>
);
};
export { ModalSearchDocs };

View File

@ -0,0 +1,38 @@
import { toAbsoluteUrl } from '@/utils';
import React from 'react';
import { Link } from 'react-router-dom';
const ModalSearchEmpty = () => {
return (
<div className="flex flex-col text-center py-9 gap-5">
<div className="flex justify-center">
<img
src={toAbsoluteUrl('/media/illustrations/33.svg')}
className="dark:hidden max-h-[113px]"
alt="image"
/>
<img
src={toAbsoluteUrl('/media/illustrations/33-dark.svg')}
className="light:hidden max-h-[113px]"
alt="image"
/>
</div>
<div className="flex flex-col gap-1.5">
<h3 className="text-base font-semibold text-gray-900 text-center">
Looking for something..
</h3>
<span className="text-2sm font-medium text-center text-gray-600">
Initiate your digital experience with <br />
our intuitive dashboard
</span>
</div>
<div className="flex justify-center">
<Link to="#" className="btn btn-sm btn-light flex justify-center">
View Projects
</Link>
</div>
</div>
);
};
export { ModalSearchEmpty };

View File

@ -0,0 +1,50 @@
import React from 'react';
import { toAbsoluteUrl } from '@/utils';
import { CommonAvatars } from '@/partials/common';
import { IModalSearchIntegrationsItem } from './types';
// Define the props interface
interface IModalSearchIntegrationsProps {
items: IModalSearchIntegrationsItem[];
}
const ModalSearchIntegrations = ({ items }: IModalSearchIntegrationsProps) => {
return (
<div className="menu menu-default p-0 flex-col">
{items.map((item, index) => (
<div className="menu-item" key={index}>
<div className="menu-link flex items-center justify-between gap-2">
<div className="flex items-center grow gap-2">
{/* Logo */}
<div className="flex items-center justify-center size-10 shrink-0 rounded-full border border-gray-200 bg-gray-100">
<img
src={toAbsoluteUrl(`/media/brand-logos/${item.logo}`)}
className="size-6 shrink-0"
alt={item.name}
/>
</div>
{/* Name and description */}
<div className="flex flex-col gap-0.5">
<a
href="#"
className="text-2sm font-semibold text-gray-900 hover:text-primary-active"
>
{item.name}
</a>
<span className="text-2xs font-medium text-gray-600">{item.description}</span>
</div>
</div>
{/* Team avatars */}
<div className="flex justify-end shrink-0">
<CommonAvatars size="size-[30px]" group={item.team} />
</div>
</div>
</div>
))}
</div>
);
};
export { ModalSearchIntegrations };

View File

@ -0,0 +1,45 @@
import React from 'react';
import {
IModalSearchIntegrationsItem,
IModalSearchSettingsItem,
IModalSearchUsersItem
} from './types';
import { ModalSearchIntegrations } from './ModalSearchIntegrations';
import { ModalSearchUsers } from './ModalSearchUsers';
import { ModalSearchSettingsItems } from './ModalSearchSettingsItems';
export interface IModalSearchMixedProps {
settings: IModalSearchSettingsItem[];
integrations: IModalSearchIntegrationsItem[];
users: IModalSearchUsersItem[];
}
const ModalSearchMixed = ({ settings, integrations, users }: IModalSearchMixedProps) => {
return (
<div className="flex flex-col gap-2.5">
<div>
<div className="text-xs text-gray-600 font-medium pt-2.5 pb-1.5 ps-5">Settings</div>
<div className="menu menu-default p-0 flex-col">
<ModalSearchSettingsItems items={settings} />
</div>
</div>
<div className="border-b border-b-gray-200"></div>
<div>
<div className="text-xs text-gray-600 font-medium pt-2.5 pb-1.5 ps-5">Integrations</div>
<ModalSearchIntegrations items={integrations} />
</div>
<div className="border-b border-b-gray-200"></div>
<div>
<div className="text-xs text-gray-600 font-medium pt-2.5 pb-1.5 ps-5">Users</div>
<ModalSearchUsers items={users} />
</div>
</div>
);
};
export { ModalSearchMixed };

View File

@ -0,0 +1,35 @@
import { toAbsoluteUrl } from '@/utils';
import React from 'react';
import { Link } from 'react-router-dom';
const ModalSearchNoResults = () => {
return (
<div className="flex flex-col text-center py-9 gap-5">
<div className="flex justify-center">
<img
src={toAbsoluteUrl('/media/illustrations/33.svg')}
className="dark:hidden max-h-[113px]"
alt="image"
/>
<img
src={toAbsoluteUrl('/media/illustrations/33-dark.svg')}
className="light:hidden max-h-[113px]"
alt="image"
/>
</div>
<div className="flex flex-col gap-1.5">
<h3 className="text-base font-semibold text-gray-900 text-center">No Results Found</h3>
<span className="text-2sm font-medium text-center text-gray-600">
Refine your query to discover relevant items
</span>
</div>
<div className="flex justify-center">
<Link to="#" className="btn btn-sm btn-light flex justify-center">
View Projects
</Link>
</div>
</div>
);
};
export { ModalSearchNoResults };

View File

@ -0,0 +1,32 @@
import React from 'react';
import { IModalSearchSettingsGroup } from './types';
import { Link } from 'react-router-dom';
import { ModalSearchSettingsItems } from './ModalSearchSettingsItems';
export interface IModalSearchSettingsProps {
items: IModalSearchSettingsGroup[];
more?: boolean;
}
const ModalSearchSettings = ({ items }: IModalSearchSettingsProps) => {
return (
<div className="menu menu-default p-0 flex-col">
{items.map((group, groupIndex) => (
<div key={groupIndex} className="pb-2.5">
{/* Group title */}
<div className="text-xs text-gray-600 font-medium pt-2.5 ps-5">{group.title}</div>
<ModalSearchSettingsItems items={group.children} />
</div>
))}
<div className="menu-item px-4 pt-2.5">
<Link to="#" className="btn btn-sm btn-light justify-center">
Go to Users
</Link>
</div>
</div>
);
};
export { ModalSearchSettings };

View File

@ -0,0 +1,26 @@
import { KeenIcon } from '@/components';
import React from 'react';
import { IModalSearchSettingsItem } from './types';
export interface IModalSearchSettingsItemsProps {
items: IModalSearchSettingsItem[];
}
const ModalSearchSettingsItems = ({ items }: IModalSearchSettingsItemsProps) => {
return (
<>
{items.map((item, index) => (
<div className="menu-item" key={index}>
<a href="#" className="menu-link">
<span className="menu-icon">
<KeenIcon icon={item.icon} />
</span>
<span className="menu-title">{item.info}</span>
</a>
</div>
))}
</>
);
};
export { ModalSearchSettingsItems };

View File

@ -0,0 +1,65 @@
import React from 'react';
import { toAbsoluteUrl } from '@/utils';
import { KeenIcon } from '@/components';
import { IModalSearchUsersItem } from './types';
interface IModalSearchUsersProps {
items: IModalSearchUsersItem[];
more?: boolean;
}
const ModalSearchUsers = ({ items, more = true }: IModalSearchUsersProps) => {
return (
<div className="menu menu-default p-0 flex-col">
<div className="grid gap-1">
{items.map((item, index) => (
<div className="menu-item" key={index}>
<div className="menu-link flex justify-between gap-2">
{/* User avatar and info */}
<div className="flex items-center gap-2.5">
<img
src={toAbsoluteUrl(`/media/avatars/${item.avatar}`)}
className="rounded-full size-9 shrink-0"
alt={item.name}
/>
<div className="flex flex-col">
<a
href="#"
className="text-sm font-semibold text-gray-900 hover:text-primary-active mb-px"
>
{item.name}
</a>
<span className="text-2sm font-normal text-gray-500">
{item.email} connections
</span>
</div>
</div>
{/* Status badge and action button */}
<div className="flex items-center gap-2.5">
<div className={`badge badge-pill badge-outline ${item.color} gap-1.5`}>
<span className={`badge badge-dot ${item.color} size-1.5`}></span>
{item.label}
</div>
<button className="btn btn-icon btn-light btn-clear btn-sm">
<KeenIcon icon="dots-vertical" />
</button>
</div>
</div>
</div>
))}
{/* Conditional "Go to Users" button */}
{!more && (
<div className="menu-item px-4 pt-2">
<a href="#" className="btn btn-sm btn-light justify-center">
Go to Users
</a>
</div>
)}
</div>
</div>
);
};
export { ModalSearchUsers };

View File

@ -0,0 +1,9 @@
export * from './ModalSearchDocs';
export * from './ModalSearchMixed';
export * from './ModalSearchSettings';
export * from './ModalSearchSettingsItems';
export * from './ModalSearchIntegrations';
export * from './ModalSearchEmpty';
export * from './ModalSearchUsers';
export * from './ModalSearchNoResults';
export * from './types';

View File

@ -0,0 +1,38 @@
import { IAvatarsItems } from '@/partials/common';
export interface IModalSearchDocsItem {
image: string;
desc: string;
date: string;
}
export interface IModalSearchSettingsItem {
icon: string;
info: string;
}
export interface IModalSearchSettingsGroup {
title: string;
children: IModalSearchSettingsItem[];
}
export interface IModalSearchIntegrationsIAvatar {
filename?: string;
fallback?: string;
variant: string;
}
export interface IModalSearchIntegrationsItem {
logo: string;
name: string;
description: string;
team: IAvatarsItems;
}
export interface IModalSearchUsersItem {
avatar: string;
name: string;
email: string;
label: string;
color: string;
}

View File

@ -0,0 +1,53 @@
import React from 'react';
import {
ModalShareProfileViaLink,
ModalShareProfileViaEmail,
ModalShareProfileUsers,
ModalShareProfileSettings
} from './';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle
} from '@/components/ui/dialog';
interface ModalShareProfileProps {
open: boolean;
onOpenChange: () => void;
}
const ModalShareProfile = ({ open, onOpenChange }: ModalShareProfileProps) => {
const scrollableHeight = 300;
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-[500px]">
<DialogHeader>
<DialogTitle>Share Profile</DialogTitle>
<DialogDescription></DialogDescription>
</DialogHeader>
<div className="grid gap-5 px-0 py-5">
<ModalShareProfileViaLink />
<div className="border-b border-b-gray-200"></div>
<ModalShareProfileViaEmail />
<div className="border-b border-b-gray-200"></div>
<div className="scrollable-y-auto" style={{ maxHeight: `${scrollableHeight}px` }}>
<ModalShareProfileUsers />
</div>
<div className="border-b border-b-gray-200"></div>
<ModalShareProfileSettings />
</div>
</DialogContent>
</Dialog>
);
};
export { ModalShareProfile };

View File

@ -0,0 +1,43 @@
import { KeenIcon } from '@/components';
import React from 'react';
import { Link } from 'react-router-dom';
const ModalShareProfileSettings = () => {
return (
<div className="flex flex-col px-5 gap-4">
<label className="text-gray-900 font-semibold text-2sm">Settings</label>
<div className="flex flex-center justify-between flex-wrap gap-2">
<div className="flex flex-center gap-1.5">
<KeenIcon icon="user" className="text-gray-500" />
<div className="flex flex-center text-gray-700 font-medium text-xs">
Anyone at
<Link to="#" className="text-xs font-medium link mx-1">
KeenThemes
</Link>
can view
</div>
</div>
<button className="btn btn-sm btn-link">Change Access</button>
</div>
<div className="flex flex-center justify-between flex-wrap gap-2 mb-1">
<div className="flex flex-center gap-1.5">
<KeenIcon icon="icon" className="text-gray-500" />
<div className="flex flex-center text-gray-700 font-medium text-xs">
Anyone with link can edit
</div>
</div>
<button className="btn btn-sm btn-link">Set Password</button>
</div>
<button className="btn btn-primary justify-center">Done</button>
</div>
);
};
export { ModalShareProfileSettings };

View File

@ -0,0 +1,74 @@
import { toAbsoluteUrl } from '@/utils';
import React from 'react';
import { Link } from 'react-router-dom';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue
} from '@/components/ui/select';
const ModalShareProfileUsers = () => {
const items = [
{
avatar: '300-3.png',
userName: 'Tyler Hero',
email: 'tyler.hero@gmail.com',
role: 'owner'
},
{
avatar: '300-1.png',
userName: 'Esther Howard',
email: 'esther.howard@gmail.com',
role: 'editor'
},
{
avatar: '300-11.png',
userName: 'Jacob Jones',
email: 'jacob.jones@gmail.com',
role: 'viewer'
}
];
return (
<div className="flex flex-col px-5 gap-2.5">
{items.map((item, index) => (
<div key={index} className="flex items-center flex-wrap gap-2">
<div className="flex items-center grow gap-2.5">
<img
src={toAbsoluteUrl(`/media/avatars/${item.avatar}`)}
className="rounded-full size-9 shrink-0"
alt={`${item.userName} avatar`}
/>
<div className="flex flex-col">
<Link
to="#"
className="text-sm font-semibold text-gray-900 hover:text-primary-active mb-px"
>
{item.userName}
</Link>
<Link to="#" className="hover:text-primary-active text-2sm font-medium text-gray-600">
{item.email}
</Link>
</div>
</div>
<Select defaultValue={item.role}>
<SelectTrigger className="w-24" size="sm">
<SelectValue placeholder="Role" />
</SelectTrigger>
<SelectContent className="w-32">
<SelectItem value="owner">Owner</SelectItem>
<SelectItem value="editor">Editor</SelectItem>
<SelectItem value="viewer">Viewer</SelectItem>
</SelectContent>
</Select>
</div>
))}
</div>
);
};
export { ModalShareProfileUsers };

View File

@ -0,0 +1,30 @@
import { KeenIcon } from '@/components';
import React, { useState } from 'react';
const ModalShareProfileViaEmail = () => {
const [emailInput, setEmailInput] = useState('');
return (
<div className="flex flex-col px-5 gap-2.5">
<div className="flex flex-center gap-1">
<label className="text-gray-900 font-semibold text-2sm">Share via email</label>
<KeenIcon icon="information-2" className="text-gray-500 text-2sm" />
</div>
<div className="flex flex-center gap-2.5">
<label className="input">
<input
type="text"
name="query"
value={emailInput}
onChange={(e) => setEmailInput(e.target.value)}
placeholder="miles.turner@gmail.com"
/>
</label>
<button className="btn btn-primary">Share</button>
</div>
</div>
);
};
export { ModalShareProfileViaEmail };

View File

@ -0,0 +1,29 @@
import { KeenIcon } from '@/components';
import React, { useState } from 'react';
const ModalShareProfileViaLink = () => {
const [linkInput, setLinkInput] = useState('');
return (
<div className="flex flex-col px-5 gap-2.5">
<div className="flex flex-center gap-1">
<label className="text-gray-900 font-semibold text-2sm">Share read-only link</label>
<KeenIcon icon="information-2" className="text-gray-500 text-2sm" />
</div>
<label className="input">
<input
type="text"
name="query"
value={linkInput}
onChange={(e) => setLinkInput(e.target.value)}
placeholder="https://metronic.com/profiles/x7g2vA3kZ5"
/>
<button className="btn btn-icon">
<KeenIcon icon="copy" />
</button>
</label>
</div>
);
};
export { ModalShareProfileViaLink };

View File

@ -0,0 +1,6 @@
export * from './ModalShareProfile';
export * from './ModalShareProfileViaLink';
export * from './ModalShareProfileViaEmail';
export * from './ModalShareProfileUsers';
export * from './ModalShareProfileSettings';
export * from './types';

View File

@ -0,0 +1,6 @@
export interface IModalShareProfileDocsItem {
avatar: string;
userName: string;
email: string;
role: string;
}

View File

@ -0,0 +1,61 @@
import {
Dialog,
DialogBody,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle
} from '@/components/ui/dialog';
import { Link } from 'react-router-dom';
import { toAbsoluteUrl } from '@/utils';
interface IModalWelcomMessageProps {
open: boolean;
onOpenChange: () => void;
}
const ModalWelcomMessage = ({ open, onOpenChange }: IModalWelcomMessageProps) => {
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-[500px]">
<DialogHeader className="border-0">
<DialogTitle></DialogTitle>
<DialogDescription></DialogDescription>
</DialogHeader>
<DialogBody className="flex flex-col items-center pt-10 pb-10">
<div className="mb-10">
<img
src={toAbsoluteUrl('/media/illustrations/21.svg')}
className="dark:hidden max-h-[140px]"
/>
<img
src={toAbsoluteUrl('/media/illustrations/21-dark.svg')}
className="light:hidden max-h-[140px]"
/>
</div>
<h3 className="text-lg font-medium text-gray-900 text-center mb-3">
Welcome to Metronic
</h3>
<div className="text-2sm text-center text-gray-700 mb-7">
We're thrilled to have you on board and excited for <br />
the journey ahead together.
</div>
<div className="flex justify-center mb-2">
<Link to="/" className="btn btn-primary flex justify-center">
Show me around
</Link>
</div>
<Link to="/" className="text-2sm font-medium text-gray-700 hover:text-primary py-3">
Skip the tour
</Link>
</DialogBody>
</DialogContent>
</Dialog>
);
};
export { ModalWelcomMessage };

View File

@ -0,0 +1 @@
export * from './ModalWelcomMessage';