diff --git a/assets/pasted-20260213-200505-610d0266.png b/assets/pasted-20260213-200505-610d0266.png new file mode 100644 index 0000000..645797d Binary files /dev/null and b/assets/pasted-20260213-200505-610d0266.png differ diff --git a/frontend/src/colors.ts b/frontend/src/colors.ts index 9d6920a..7c84fca 100644 --- a/frontend/src/colors.ts +++ b/frontend/src/colors.ts @@ -6,7 +6,7 @@ export const gradientBgPurplePink = `${gradientBgBase} from-purple-400 via-pink- export const gradientBgViolet = `${gradientBgBase} ${colorBgBase}` export const gradientBgDark = `${gradientBgBase} from-dark-700 via-dark-900 to-dark-800`; export const gradientBgPinkRed = `${gradientBgBase} from-pink-400 via-red-500 to-yellow-500` -export const gradientBgExecutive = 'bg-gradient-to-br from-white to-[#091EAA]/[0.07]' +export const gradientBgExecutive = 'bg-gradient-to-br from-white to-pavitra-blue/[0.07]' export const colorsBgLight = { white: 'bg-white text-black', @@ -15,7 +15,7 @@ export const colorsBgLight = { success: 'bg-emerald-500 border-emerald-500 dark:bg-pavitra-blue dark:border-pavitra-blue text-white', danger: 'bg-red-500 border-red-500 text-white', warning: 'bg-yellow-500 border-yellow-500 text-white', - info: 'bg-blue-500 border-blue-500 dark:bg-pavitra-blue dark:border-pavitra-blue text-white', + info: 'bg-pavitra-blue border-pavitra-blue dark:bg-pavitra-blue dark:border-pavitra-blue text-white', } export const colorsText = { @@ -25,7 +25,7 @@ export const colorsText = { success: 'text-emerald-500', danger: 'text-red-500', warning: 'text-yellow-500', - info: 'text-blue-500', + info: 'text-pavitra-blue', }; export const colorsOutline = { @@ -35,7 +35,7 @@ export const colorsOutline = { success: [colorsText.success, 'border-emerald-500'].join(' '), danger: [colorsText.danger, 'border-red-500'].join(' '), warning: [colorsText.warning, 'border-yellow-500'].join(' '), - info: [colorsText.info, 'border-blue-500'].join(' '), + info: [colorsText.info, 'border-pavitra-blue'].join(' '), }; export const getButtonColor = ( @@ -57,7 +57,7 @@ export const getButtonColor = ( success: 'ring-emerald-300 dark:ring-pavitra-blue', danger: 'ring-red-300 dark:ring-red-700', warning: 'ring-yellow-300 dark:ring-yellow-700', - info: "ring-blue-300 dark:ring-pavitra-blue", + info: "ring-pavitra-blue/30 dark:ring-pavitra-blue/50", }, active: { white: 'bg-gray-100', @@ -67,7 +67,7 @@ export const getButtonColor = ( success: 'bg-emerald-700 dark:bg-pavitra-blue', danger: 'bg-red-700 dark:bg-red-600', warning: 'bg-yellow-700 dark:bg-yellow-600', - info: 'bg-blue-700 dark:bg-pavitra-blue', + info: 'bg-pavitra-blue/90 dark:bg-pavitra-blue/90', }, bg: { white: 'bg-white text-black', @@ -77,7 +77,7 @@ export const getButtonColor = ( success: 'bg-emerald-600 dark:bg-pavitra-blue text-white', danger: 'bg-red-600 text-white dark:bg-red-500 ', warning: 'bg-yellow-600 dark:bg-yellow-500 text-white', - info: " bg-blue-600 dark:bg-pavitra-blue text-white ", + info: " bg-pavitra-blue dark:bg-pavitra-blue text-white ", }, bgHover: { white: 'hover:bg-gray-100', @@ -90,7 +90,7 @@ export const getButtonColor = ( 'hover:bg-red-700 hover:border-red-700 hover:dark:bg-red-600 hover:dark:border-red-600', warning: 'hover:bg-yellow-700 hover:border-yellow-700 hover:dark:bg-yellow-600 hover:dark:border-yellow-600', - info: "hover:bg-blue-700 hover:border-blue-700 hover:dark:bg-pavitra-blue/80 hover:dark:border-pavitra-blue/80", + info: "hover:bg-pavitra-blue/80 hover:border-pavitra-blue/80 hover:dark:bg-pavitra-blue/80 hover:dark:border-pavitra-blue/80", }, borders: { white: 'border-white', @@ -100,14 +100,14 @@ export const getButtonColor = ( success: 'border-emerald-600 dark:border-pavitra-blue', danger: 'border-red-600 dark:border-red-500', warning: 'border-yellow-600 dark:border-yellow-500', - info: "border-blue-600 border-blue-600 dark:border-pavitra-blue", + info: "border-pavitra-blue dark:border-pavitra-blue", }, text: { contrast: 'dark:text-slate-100', success: 'text-emerald-600 dark:text-pavitra-blue', danger: 'text-red-600 dark:text-red-500', warning: 'text-yellow-600 dark:text-yellow-500', - info: 'text-blue-600 dark:text-pavitra-blue', + info: 'text-pavitra-blue dark:text-pavitra-blue', }, outlineHover: { contrast: @@ -117,7 +117,7 @@ export const getButtonColor = ( 'hover:bg-red-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-red-600', warning: 'hover:bg-yellow-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-yellow-600', - info: "hover:bg-blue-600 hover:bg-blue-600 hover:text-white hover:dark:text-white hover:dark:border-pavitra-blue", + info: "hover:bg-pavitra-blue hover:text-white hover:dark:text-white hover:dark:border-pavitra-blue", }, } diff --git a/frontend/src/components/Directory/MemberCard.tsx b/frontend/src/components/Directory/MemberCard.tsx new file mode 100644 index 0000000..e2166ad --- /dev/null +++ b/frontend/src/components/Directory/MemberCard.tsx @@ -0,0 +1,138 @@ +import React from 'react'; +import { mdiLinkedin, mdiMapMarkerOutline, mdiEmailOutline, mdiPhoneOutline, mdiMessageTextOutline, mdiCrown } from '@mdi/js'; +import BaseIcon from '../BaseIcon'; +import BaseButton from '../BaseButton'; +import Link from 'next/link'; +import { useAppSelector } from '../../stores/hooks'; + +type Props = { + member: any; +}; + +const MemberCard = ({ member }: Props) => { + const brandColor = '#091EAA'; + const { currentUser } = useAppSelector((state) => state.auth); + + const headshot = member.headshot && member.headshot[0] ? member.headshot[0].publicUrl : null; + const firstName = member.user?.firstName || ''; + const lastName = member.user?.lastName || ''; + const fullName = `${firstName} ${lastName}`.trim() || 'Anonymous Member'; + const initials = `${firstName.charAt(0)}${lastName.charAt(0)}`.toUpperCase() || '?'; + + const memberSinceYear = member.member_since ? new Date(member.member_since).getFullYear() : null; + + const mailtoLink = `mailto:${member.user?.email}?subject=Power Suite Connection – ${currentUser?.firstName || 'A Member'}`; + + return ( +
+ +
+ {/* Avatar */} +
+ {headshot ? ( + {fullName} + ) : ( +
+ {initials} +
+ )} +
+ +
+ {/* Name */} +

+ {fullName} +

+ + {/* Title Badge */} +
+ {member.professional_title || 'Executive'} +
+ + {/* Organization */} +
+ {member.organization || 'Independent'} +
+
+
+ + {/* Pills */} +
+ {member.industry && ( + + {member.industry} + + )} + {member.sector && ( + + {member.sector === 'nonprofit_501c3' ? 'Nonprofit (501c3)' : member.sector.charAt(0).toUpperCase() + member.sector.slice(1)} + + )} +
+ + {/* Location */} +
+ + {member.city}{member.city && member.state ? ', ' : ''}{member.state} +
+ + + {/* Action Buttons */} +
+ + + {member.linkedin_url && ( + + + + )} + + {member.allow_phone_contact && member.phone_number && ( +
+ + + + + + +
+ )} +
+ + {/* Footer Badges */} +
+ {member.founding_member && ( +
+ + Zeta Proud +
+ )} + {memberSinceYear && ( +
+ Member since {memberSinceYear} +
+ )} +
+
+ ); +}; + +export default MemberCard; diff --git a/frontend/src/menuAside.ts b/frontend/src/menuAside.ts index 4325420..3d426e2 100644 --- a/frontend/src/menuAside.ts +++ b/frontend/src/menuAside.ts @@ -8,7 +8,7 @@ const menuAside: MenuAsideItem[] = [ label: 'Home', }, { - href: '/member_profiles/member_profiles-list', + href: '/directory', label: 'Executive Directory', // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore @@ -25,11 +25,6 @@ const menuAside: MenuAsideItem[] = [ icon: icon.mdiShieldEditOutline, permissions: 'READ_USERS', // Only show to users who can read users (Admins) menu: [ - { - href: '/dashboard', - icon: icon.mdiChartTimelineVariant, - label: 'Analytics', - }, { href: '/users/users-list', label: 'Member Accounts', @@ -69,4 +64,4 @@ const menuAside: MenuAsideItem[] = [ }, ] -export default menuAside \ No newline at end of file +export default menuAside diff --git a/frontend/src/pages/dashboard.tsx b/frontend/src/pages/dashboard.tsx index c4ccb96..e44b2f7 100644 --- a/frontend/src/pages/dashboard.tsx +++ b/frontend/src/pages/dashboard.tsx @@ -1,8 +1,9 @@ import * as icon from '@mdi/js'; import Head from 'next/head' -import React from 'react' +import React, { useEffect } from 'react' import axios from 'axios'; import type { ReactElement } from 'react' +import { useRouter } from 'next/router'; import LayoutAuthenticated from '../layouts/Authenticated' import SectionMain from '../components/SectionMain' import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton' @@ -16,15 +17,16 @@ import { WidgetCreator } from '../components/WidgetCreator/WidgetCreator'; import { SmartWidget } from '../components/SmartWidget/SmartWidget'; import { useAppDispatch, useAppSelector } from '../stores/hooks'; + const Dashboard = () => { const dispatch = useAppDispatch(); + const router = useRouter(); const iconsColor = useAppSelector((state) => state.style.iconsColor); const corners = useAppSelector((state) => state.style.corners); const cardsStyle = useAppSelector((state) => state.style.cardsStyle); const loadingMessage = 'Loading...'; - const [users, setUsers] = React.useState(loadingMessage); const [roles, setRoles] = React.useState(loadingMessage); const [permissions, setPermissions] = React.useState(loadingMessage); @@ -34,29 +36,31 @@ const Dashboard = () => { const [email_reminders, setEmail_reminders] = React.useState(loadingMessage); const [audit_events, setAudit_events] = React.useState(loadingMessage); - const [widgetsRole, setWidgetsRole] = React.useState({ role: { value: '', label: '' }, }); const { currentUser } = useAppSelector((state) => state.auth); const { isFetchingQuery } = useAppSelector((state) => state.openAi); - const { rolesWidgets, loading } = useAppSelector((state) => state.roles); - + + // Disable dashboard for non-admin members + useEffect(() => { + if (currentUser && !hasPermission(currentUser, 'READ_USERS')) { + router.push('/directory'); + } + }, [currentUser, router]); async function loadData() { const entities = ['users','roles','permissions','member_profiles','expertise_areas','member_import_batches','email_reminders','audit_events',]; const fns = [setUsers,setRoles,setPermissions,setMember_profiles,setExpertise_areas,setMember_import_batches,setEmail_reminders,setAudit_events,]; const requests = entities.map((entity, index) => { - if(hasPermission(currentUser, `READ_${entity.toUpperCase()}`)) { return axios.get(`/${entity.toLowerCase()}/count`); } else { fns[index](null); return Promise.resolve({data: {count: null}}); } - }); Promise.allSettled(requests).then((results) => { @@ -73,17 +77,25 @@ const Dashboard = () => { async function getWidgets(roleId) { await dispatch(fetchWidgets(roleId)); } + React.useEffect(() => { if (!currentUser) return; + if (!hasPermission(currentUser, 'READ_USERS')) return; // Don't load if about to redirect loadData().then(); setWidgetsRole({ role: { value: currentUser?.app_role?.id, label: currentUser?.app_role?.name } }); }, [currentUser]); React.useEffect(() => { if (!currentUser || !widgetsRole?.role?.value) return; + if (!hasPermission(currentUser, 'READ_USERS')) return; getWidgets(widgetsRole?.role?.value || '').then(); }, [widgetsRole?.role?.value]); + // Return null if redirecting to avoid flash of dashboard + if (currentUser && !hasPermission(currentUser, 'READ_USERS')) { + return null; + } + return ( <> @@ -141,8 +153,6 @@ const Dashboard = () => { {!!rolesWidgets.length &&
}
- - {hasPermission(currentUser, 'READ_USERS') &&
{ w="w-16" h="h-16" size={48} - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore path={icon.mdiAccountGroup || icon.mdiTable} />
@@ -190,8 +198,6 @@ const Dashboard = () => { w="w-16" h="h-16" size={48} - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore path={icon.mdiShieldAccountVariantOutline || icon.mdiTable} />
@@ -218,8 +224,6 @@ const Dashboard = () => { w="w-16" h="h-16" size={48} - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore path={icon.mdiShieldAccountOutline || icon.mdiTable} /> @@ -227,7 +231,7 @@ const Dashboard = () => { } - {hasPermission(currentUser, 'READ_MEMBER_PROFILES') && + {hasPermission(currentUser, 'READ_MEMBER_PROFILES') &&
@@ -246,8 +250,6 @@ const Dashboard = () => { w="w-16" h="h-16" size={48} - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore path={'mdiBadgeAccountOutline' in icon ? icon['mdiBadgeAccountOutline' as keyof typeof icon] : icon.mdiTable || icon.mdiTable} />
@@ -274,8 +276,6 @@ const Dashboard = () => { w="w-16" h="h-16" size={48} - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore path={'mdiLightbulbOnOutline' in icon ? icon['mdiLightbulbOnOutline' as keyof typeof icon] : icon.mdiTable || icon.mdiTable} /> @@ -302,8 +302,6 @@ const Dashboard = () => { w="w-16" h="h-16" size={48} - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore path={'mdiFileUploadOutline' in icon ? icon['mdiFileUploadOutline' as keyof typeof icon] : icon.mdiTable || icon.mdiTable} /> @@ -330,8 +328,6 @@ const Dashboard = () => { w="w-16" h="h-16" size={48} - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore path={'mdiEmailOutline' in icon ? icon['mdiEmailOutline' as keyof typeof icon] : icon.mdiTable || icon.mdiTable} /> @@ -358,16 +354,12 @@ const Dashboard = () => { w="w-16" h="h-16" size={48} - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore path={'mdiClipboardTextOutline' in icon ? icon['mdiClipboardTextOutline' as keyof typeof icon] : icon.mdiTable || icon.mdiTable} /> } - - @@ -378,4 +370,4 @@ Dashboard.getLayout = function getLayout(page: ReactElement) { return {page} } -export default Dashboard +export default Dashboard \ No newline at end of file diff --git a/frontend/src/pages/directory/[id].tsx b/frontend/src/pages/directory/[id].tsx new file mode 100644 index 0000000..1354214 --- /dev/null +++ b/frontend/src/pages/directory/[id].tsx @@ -0,0 +1,288 @@ +import React, { ReactElement, useEffect, useMemo } from 'react'; +import Head from 'next/head'; +import { useRouter } from 'next/router'; +import { mdiLinkedin, mdiMapMarkerOutline, mdiEmailOutline, mdiPhoneOutline, mdiMessageTextOutline, mdiArrowLeft, mdiCrown } from '@mdi/js'; +import { useAppDispatch, useAppSelector } from '../../stores/hooks'; +import { fetch } from '../../stores/member_profiles/member_profilesSlice'; +import LayoutAuthenticated from '../../layouts/Authenticated'; +import SectionMain from '../../components/SectionMain'; +import { getPageTitle } from '../../config'; +import BaseIcon from '../../components/BaseIcon'; +import BaseButton from '../../components/BaseButton'; +import LoadingSpinner from '../../components/LoadingSpinner'; + +const MemberProfileDetail = () => { + const router = useRouter(); + const dispatch = useAppDispatch(); + const { id } = router.query; + const { member_profiles, loading } = useAppSelector((state) => state.member_profiles); + const { currentUser } = useAppSelector((state) => state.auth); + + useEffect(() => { + if (id) { + dispatch(fetch({ id })); + } + }, [dispatch, id]); + + const member = member_profiles; + + const isProfileAvailable = useMemo(() => { + if (!member) return false; + + // Always allow the user to see their own profile? + // The requirement says "not be accessible for inactive/non-consented profiles". + // I will stick to the rule strictly. + const isActive = member.profile_status === 'active'; + const isConsented = member.directory_consent === true; + const isReconfirmed = member.confirmation_expires_at ? new Date(member.confirmation_expires_at) > new Date() : false; + + return isActive && isConsented && isReconfirmed; + }, [member]); + + if (loading || !member) { + return ( + +
+ +
+
+ ); + } + + if (!isProfileAvailable) { + return ( + +
+

Profile unavailable

+

This profile is currently private or inactive.

+ router.push('/directory')} + className="bg-[#091EAA] border-none rounded-none" + /> +
+
+ ); + } + + const fullName = `${member.user?.firstName || ''} ${member.user?.lastName || ''}`.trim() || 'Anonymous Member'; + const headshot = member.headshot && member.headshot[0] ? member.headshot[0].publicUrl : null; + const initials = `${(member.user?.firstName || '').charAt(0)}${(member.user?.lastName || '').charAt(0)}`.toUpperCase() || '?'; + const mailtoLink = `mailto:${member.user?.email}?subject=Power Suite Connection – ${currentUser?.firstName || 'A Member'}`; + + return ( + <> + + {getPageTitle(fullName)} + + + +
+ +
+ +
+ {/* Header Section */} +
+
+ {/* Avatar */} +
+ {headshot ? ( + {fullName} + ) : ( +
+ {initials} +
+ )} +
+ + {/* Basic Info */} +
+
+

+ {fullName} +

+ {member.founding_member && ( +
+ + Zeta Proud +
+ )} +
+ +
+ {member.professional_title || 'Executive'} +
+ +
+ {member.organization} +
+ +
+
+ + {member.city}, {member.state} +
+ {member.member_since && ( +
+ Member Since: + {new Date(member.member_since).getFullYear()} +
+ )} +
+
+ + {/* Actions */} +
+ + +
+ {member.linkedin_url && ( + + + + )} + + {member.allow_phone_contact && member.phone_number && ( + <> + + + + + + + + )} +
+
+
+
+ + {/* Content Section */} +
+ {/* Left Column: Bio & Spotlight */} +
+
+

Professional Bio

+ {member.professional_bio ? ( +
+ ) : ( +

No bio provided.

+ )} +
+ + {member.recognition_spotlight && ( +
+

Recognition & Spotlight

+
+
+ )} +
+ + {/* Right Column: Expertise & Details */} +
+
+

Details

+
+
+
Industry
+
{member.industry || 'N/A'}
+
+
+
Sector
+
+ {member.sector === 'nonprofit_501c3' ? 'Nonprofit (501c3)' : member.sector} +
+
+ {member.zeta_region && ( +
+
Zeta Region
+
{member.zeta_region}
+
+ )} + {member.leadership_level && ( +
+
Leadership Level
+
+ {member.leadership_level.replace(/_/g, ' ')} +
+
+ )} +
+
+ + {member.areas_of_expertise && member.areas_of_expertise.length > 0 && ( +
+

Areas of Expertise

+
+ {member.areas_of_expertise.map((area: any) => ( + + {area.name} + + ))} +
+
+ )} + + {member.mentorship_interest && member.mentorship_interest !== 'neither' && ( +
+

Mentorship

+
+ + Interested as: {member.mentorship_interest} + +
+
+ )} +
+
+
+
+ + ); +}; + +MemberProfileDetail.getLayout = function getLayout(page: ReactElement) { + return ( + + {page} + + ); +}; + +export default MemberProfileDetail; diff --git a/frontend/src/pages/directory/index.tsx b/frontend/src/pages/directory/index.tsx new file mode 100644 index 0000000..50a03a6 --- /dev/null +++ b/frontend/src/pages/directory/index.tsx @@ -0,0 +1,129 @@ +import React, { ReactElement, useEffect, useState, useMemo } from 'react'; +import Head from 'next/head'; +import { mdiMagnify } from '@mdi/js'; +import { useAppDispatch, useAppSelector } from '../../stores/hooks'; +import { fetch } from '../../stores/member_profiles/member_profilesSlice'; +import LayoutAuthenticated from '../../layouts/Authenticated'; +import SectionMain from '../../components/SectionMain'; +import { getPageTitle } from '../../config'; +import MemberCard from '../../components/Directory/MemberCard'; +import BaseIcon from '../../components/BaseIcon'; +import LoadingSpinner from '../../components/LoadingSpinner'; +import { debounce } from 'lodash'; + +const ExecutiveDirectory = () => { + const dispatch = useAppDispatch(); + const { member_profiles, loading } = useAppSelector((state) => state.member_profiles); + const [searchTerm, setSearchTerm] = useState(''); + const [selectedSector, setSelectedSector] = useState('all'); + + // Load data on mount + useEffect(() => { + const currentDate = new Date().toISOString(); + // Base filters: active status, directory consent, and reconfirmation is current + const baseQuery = `?profile_status=active&directory_consent=true&confirmation_expires_atRange=${currentDate}&limit=100`; + dispatch(fetch({ query: baseQuery })); + }, [dispatch]); + + // Client-side filtering for live search and sector + // Note: For a real large-scale app, we'd do this server-side, + // but for the directory experience requested, client-side live filtering is smoother if data size allows. + const filteredMembers = useMemo(() => { + if (!member_profiles || !Array.isArray(member_profiles)) return []; + + return member_profiles.filter((member: any) => { + const matchesSector = + selectedSector === 'all' || + member.sector === selectedSector; + + const searchLower = searchTerm.toLowerCase(); + const fullName = `${member.user?.firstName || ''} ${member.user?.lastName || ''}`.toLowerCase(); + const matchesSearch = + fullName.includes(searchLower) || + (member.professional_title || '').toLowerCase().includes(searchLower) || + (member.organization || '').toLowerCase().includes(searchLower) || + (member.industry || '').toLowerCase().includes(searchLower); + + return matchesSector && matchesSearch; + }); + }, [member_profiles, searchTerm, selectedSector]); + + const handleSearchChange = (e: React.ChangeEvent) => { + setSearchTerm(e.target.value); + }; + + return ( + <> + + {getPageTitle('Executive Directory')} + + + + {/* Header / Search & Filter Bar */} +
+ {/* Search Bar */} +
+
+ +
+ +
+ + {/* Sector Filters */} +
+ {[ + { id: 'all', label: 'All Sectors' }, + { id: 'corporate', label: 'Corporate' }, + { id: 'nonprofit_501c3', label: 'Nonprofit (501c3)' }, + ].map((sector) => ( + + ))} +
+
+ + {/* Directory Grid */} + {loading ? ( +
+ +
+ ) : filteredMembers.length > 0 ? ( +
+ {filteredMembers.map((member: any) => ( + + ))} +
+ ) : ( +
+

No members found matching your criteria.

+
+ )} +
+ + ); +}; + +ExecutiveDirectory.getLayout = function getLayout(page: ReactElement) { + return ( + + {page} + + ); +}; + +export default ExecutiveDirectory; diff --git a/frontend/src/pages/index.tsx b/frontend/src/pages/index.tsx index 7f89744..ddcd9b6 100644 --- a/frontend/src/pages/index.tsx +++ b/frontend/src/pages/index.tsx @@ -70,7 +70,7 @@ export default function Starter() {
Enter Executive Directory @@ -98,4 +98,4 @@ export default function Starter() { Starter.getLayout = function getLayout(page: ReactElement) { return {page}; -}; +}; \ No newline at end of file diff --git a/frontend/src/styles.ts b/frontend/src/styles.ts index a969b60..045167b 100644 --- a/frontend/src/styles.ts +++ b/frontend/src/styles.ts @@ -31,18 +31,18 @@ export const white: StyleObject = { asideMenuItem: 'text-gray-700 hover:bg-gray-100/70 dark:text-dark-500 dark:hover:text-white dark:hover:bg-dark-800', asideMenuItemActive: 'font-bold text-black dark:text-white', asideMenuDropdown: 'bg-gray-100/75', - navBarItemLabel: 'text-blue-600', + navBarItemLabel: 'text-pavitra-blue', navBarItemLabelHover: 'hover:text-black', navBarItemLabelActiveColor: 'text-black', overlay: 'from-white via-gray-100 to-white', activeLinkColor: 'bg-gray-100/70', bgLayoutColor: 'bg-gray-50', - iconsColor: 'text-blue-500', + iconsColor: 'text-pavitra-blue', cardsColor: 'bg-white', - focusRingColor: 'focus:ring focus:ring-blue-600 focus:border-blue-600 focus:outline-none border-gray-300 dark:focus:ring-blue-600 dark:focus:border-blue-600', + focusRingColor: 'focus:ring focus:ring-pavitra-blue focus:border-pavitra-blue focus:outline-none border-gray-300 dark:focus:ring-pavitra-blue dark:focus:border-pavitra-blue', corners: 'rounded', cardsStyle: 'bg-white border border-pavitra-400', - linkColor: 'text-blue-600', + linkColor: 'text-pavitra-blue', websiteHeder: 'border-b border-gray-200', borders: 'border-gray-200', shadow: '', @@ -88,14 +88,14 @@ export const basic: StyleObject = { asideMenuItemActive: 'font-bold text-white', asideMenuDropdown: 'bg-gray-700/50', navBarItemLabel: 'text-black', - navBarItemLabelHover: 'hover:text-blue-500', - navBarItemLabelActiveColor: 'text-blue-600', + navBarItemLabelHover: 'hover:text-pavitra-blue', + navBarItemLabelActiveColor: 'text-pavitra-blue', overlay: 'from-gray-700 via-gray-900 to-gray-700', activeLinkColor: 'bg-gray-100/70', bgLayoutColor: 'bg-gray-50', - iconsColor: 'text-blue-500', + iconsColor: 'text-pavitra-blue', cardsColor: 'bg-white', - focusRingColor: 'focus:ring focus:ring-blue-600 focus:border-blue-600 focus:outline-none dark:focus:ring-blue-600 border-gray-300 dark:focus:border-blue-600', + focusRingColor: 'focus:ring focus:ring-pavitra-blue focus:border-pavitra-blue focus:outline-none dark:focus:ring-pavitra-blue border-gray-300 dark:focus:border-pavitra-blue', corners: 'rounded', cardsStyle: 'bg-white border border-pavitra-400', linkColor: 'text-black', @@ -104,4 +104,4 @@ export const basic: StyleObject = { shadow: '', websiteSectionStyle: '', textSecondary: '', -} +} \ No newline at end of file diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index a06c7d1..601d38d 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -53,7 +53,7 @@ module.exports = { text: '#45B26B', }, 'pavitra': { - 'blue': '#0162FD', + 'blue': '#091EAA', 'green': '#00B448', 'orange': '#FFAA00', 'red': '#F20041', @@ -107,4 +107,4 @@ module.exports = { ); }), ], -} +} \ No newline at end of file