From a99d13309f883f7213e3f24c215c0198c38f0e1f Mon Sep 17 00:00:00 2001 From: Usman Baig Date: Tue, 10 Mar 2026 01:32:00 +0100 Subject: [PATCH] Improve expanded modals: wider, taller, hover percentage, click-to-filter - Widen modals from max-w-lg to max-w-2xl - Increase max height from 60vh to 80vh - Add hover percentage on each row (matching card behavior) - Click any row to filter dashboard and close modal --- components/dashboard/Campaigns.tsx | 42 ++++++++++++---------- components/dashboard/ContentStats.tsx | 47 +++++++++++++----------- components/dashboard/Locations.tsx | 51 ++++++++++++++++++--------- components/dashboard/TechSpecs.tsx | 42 +++++++++++++++------- components/dashboard/TopReferrers.tsx | 26 ++++++++++---- 5 files changed, 133 insertions(+), 75 deletions(-) diff --git a/components/dashboard/Campaigns.tsx b/components/dashboard/Campaigns.tsx index ef5eb3d..ae0894a 100644 --- a/components/dashboard/Campaigns.tsx +++ b/components/dashboard/Campaigns.tsx @@ -213,27 +213,30 @@ export default function Campaigns({ siteId, dateRange, filters, onFilter }: Camp isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} title="All Campaigns" + className="max-w-2xl" > -
+
{isLoadingFull ? (
- ) : ( - <> -
- -
- {sortedFullData.map((item) => { - return ( + ) : (() => { + const modalTotal = sortedFullData.reduce((sum, item) => sum + item.visitors, 0) + return ( + <> +
+ +
+ {sortedFullData.map((item) => (
{ if (onFilter) { onFilter({ dimension: 'utm_source', operator: 'is', values: [item.source] }); setIsModalOpen(false) } }} + className={`flex items-center justify-between py-2 group hover:bg-neutral-50 dark:hover:bg-neutral-800 rounded-lg px-2 -mx-2 transition-colors${onFilter ? ' cursor-pointer' : ''}`} >
{renderSourceIcon(item.source)} @@ -249,6 +252,9 @@ export default function Campaigns({ siteId, dateRange, filters, onFilter }: Camp
+ + {modalTotal > 0 ? `${Math.round((item.visitors / modalTotal) * 100)}%` : ''} + {formatNumber(item.visitors)} @@ -257,10 +263,10 @@ export default function Campaigns({ siteId, dateRange, filters, onFilter }: Camp
- ) - })} - - )} + ))} + + ) + })()}
diff --git a/components/dashboard/ContentStats.tsx b/components/dashboard/ContentStats.tsx index 272e25b..4295a9d 100644 --- a/components/dashboard/ContentStats.tsx +++ b/components/dashboard/ContentStats.tsx @@ -197,32 +197,39 @@ export default function ContentStats({ topPages, entryPages, exitPages, domain, isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} title={`Pages - ${getTabLabel(activeTab)}`} + className="max-w-2xl" > -
+
{isLoadingFull ? (
- ) : ( - (fullData.length > 0 ? fullData : data).map((page) => ( -
-
- - {page.path} - - + ) : (() => { + const modalData = fullData.length > 0 ? fullData : data + const modalTotal = modalData.reduce((sum, p) => sum + p.pageviews, 0) + return modalData.map((page) => { + const canFilter = onFilter && page.path + return ( +
{ if (canFilter) { onFilter({ dimension: 'path', operator: 'is', values: [page.path] }); setIsModalOpen(false) } }} + className={`flex items-center justify-between h-9 group hover:bg-neutral-50 dark:hover:bg-neutral-800 rounded-lg px-2 -mx-2 transition-colors${canFilter ? ' cursor-pointer' : ''}`} + > +
+ {page.path} +
+
+ + {modalTotal > 0 ? `${Math.round((page.pageviews / modalTotal) * 100)}%` : ''} + + + {formatNumber(page.pageviews)} + +
-
- {formatNumber(page.pageviews)} -
-
- )) - )} + ) + }) + })()}
diff --git a/components/dashboard/Locations.tsx b/components/dashboard/Locations.tsx index e5bad73..717383b 100644 --- a/components/dashboard/Locations.tsx +++ b/components/dashboard/Locations.tsx @@ -322,29 +322,46 @@ export default function Locations({ countries, cities, regions, geoDataLevel = ' isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} title={`Locations - ${activeTab.charAt(0).toUpperCase() + activeTab.slice(1)}`} + className="max-w-2xl" > -
+
{isLoadingFull ? (
- ) : ( - (fullData.length > 0 ? fullData : data).map((item) => ( -
-
- {getFlagComponent(item.country ?? '')} - - {activeTab === 'countries' ? getCountryName(item.country ?? '') : - activeTab === 'regions' ? getRegionName(item.region ?? '', item.country ?? '') : - getCityName(item.city ?? '')} - + ) : (() => { + const modalData = fullData.length > 0 ? fullData : data + const modalTotal = modalData.reduce((sum, item) => sum + item.pageviews, 0) + return modalData.map((item) => { + const dim = TAB_TO_DIMENSION[activeTab] + const filterValue = activeTab === 'countries' ? item.country : activeTab === 'regions' ? item.region : item.city + const canFilter = onFilter && dim && filterValue + return ( +
{ if (canFilter) { onFilter({ dimension: dim, operator: 'is', values: [filterValue!] }); setIsModalOpen(false) } }} + className={`flex items-center justify-between h-9 group hover:bg-neutral-50 dark:hover:bg-neutral-800 rounded-lg px-2 -mx-2 transition-colors${canFilter ? ' cursor-pointer' : ''}`} + > +
+ {getFlagComponent(item.country ?? '')} + + {activeTab === 'countries' ? getCountryName(item.country ?? '') : + activeTab === 'regions' ? getRegionName(item.region ?? '', item.country ?? '') : + getCityName(item.city ?? '')} + +
+
+ + {modalTotal > 0 ? `${Math.round((item.pageviews / modalTotal) * 100)}%` : ''} + + + {formatNumber(item.pageviews)} + +
-
- {formatNumber(item.pageviews)} -
-
- )) - )} + ) + }) + })()}
diff --git a/components/dashboard/TechSpecs.tsx b/components/dashboard/TechSpecs.tsx index ef18bc7..880548d 100644 --- a/components/dashboard/TechSpecs.tsx +++ b/components/dashboard/TechSpecs.tsx @@ -223,25 +223,41 @@ export default function TechSpecs({ browsers, os, devices, screenResolutions, co isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} title={`Technology - ${activeTab.charAt(0).toUpperCase() + activeTab.slice(1)}`} + className="max-w-2xl" > -
+
{isLoadingFull ? (
- ) : ( - (fullData.length > 0 ? fullData : data).map((item) => ( -
-
- {item.icon && {item.icon}} - {capitalize(item.name)} + ) : (() => { + const modalData = fullData.length > 0 ? fullData : data + const modalTotal = modalData.reduce((sum, item) => sum + item.pageviews, 0) + const dim = TAB_TO_DIMENSION[activeTab] + return modalData.map((item) => { + const canFilter = onFilter && dim + return ( +
{ if (canFilter) { onFilter({ dimension: dim, operator: 'is', values: [item.name] }); setIsModalOpen(false) } }} + className={`flex items-center justify-between h-9 group hover:bg-neutral-50 dark:hover:bg-neutral-800 rounded-lg px-2 -mx-2 transition-colors${canFilter ? ' cursor-pointer' : ''}`} + > +
+ {item.icon && {item.icon}} + {capitalize(item.name)} +
+
+ + {modalTotal > 0 ? `${Math.round((item.pageviews / modalTotal) * 100)}%` : ''} + + + {formatNumber(item.pageviews)} + +
-
- {formatNumber(item.pageviews)} -
-
- )) - )} + ) + }) + })()}
diff --git a/components/dashboard/TopReferrers.tsx b/components/dashboard/TopReferrers.tsx index d31ba02..15918ef 100644 --- a/components/dashboard/TopReferrers.tsx +++ b/components/dashboard/TopReferrers.tsx @@ -153,25 +153,37 @@ export default function TopReferrers({ referrers, collectReferrers = true, siteI isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} title="Referrers" + className="max-w-2xl" > -
+
{isLoadingFull ? (
- ) : ( - mergeReferrersByDisplayName(fullData.length > 0 ? fullData : filteredReferrers).map((ref) => ( -
+ ) : (() => { + const modalData = mergeReferrersByDisplayName(fullData.length > 0 ? fullData : filteredReferrers) + const modalTotal = modalData.reduce((sum, r) => sum + r.pageviews, 0) + return modalData.map((ref) => ( +
{ if (onFilter) { onFilter({ dimension: 'referrer', operator: 'is', values: [ref.referrer] }); setIsModalOpen(false) } }} + className={`flex items-center justify-between h-9 group hover:bg-neutral-50 dark:hover:bg-neutral-800 rounded-lg px-2 -mx-2 transition-colors${onFilter ? ' cursor-pointer' : ''}`} + >
{renderReferrerIcon(ref.referrer)} {getReferrerDisplayName(ref.referrer)}
-
- {formatNumber(ref.pageviews)} +
+ + {modalTotal > 0 ? `${Math.round((ref.pageviews / modalTotal) * 100)}%` : ''} + + + {formatNumber(ref.pageviews)} +
)) - )} + })()}