diff --git a/packages/design-system/src/components/table/components/tableBody/bodyCell.tsx b/packages/design-system/src/components/table/components/tableBody/bodyCell.tsx
index c0da64279..1d3877378 100644
--- a/packages/design-system/src/components/table/components/tableBody/bodyCell.tsx
+++ b/packages/design-system/src/components/table/components/tableBody/bodyCell.tsx
@@ -27,8 +27,6 @@ import type { TableRow } from '../../useTable';
interface BodyCellProps {
cell?: () => React.JSX.Element;
width: number;
- isHighlighted?: boolean;
- isRowFocused: boolean;
row: TableRow;
hasIcon?: boolean;
showIcon?: boolean | null;
@@ -42,12 +40,10 @@ interface BodyCellProps {
const BodyCell = ({
cell,
width,
- isRowFocused,
row,
hasIcon = false,
showIcon = false,
icon,
- isHighlighted = false,
rowHeightClass,
}: BodyCellProps) => {
const IconElement = icon?.Element;
@@ -70,13 +66,9 @@ const BodyCell = ({
e.stopPropagation();
}
}}
- className={`flex box-border outline-0 px-1 py-px text-xs ${
- isHighlighted
- ? `${
- isRowFocused ? 'text-white' : 'dark:text-dirty-red text-dirty-red'
- }`
- : 'dark:text-bright-gray'
- } cursor-default flex-1 ${rowHeightClass ?? 'h-5'}`}
+ className={`flex box-border outline-0 px-1 py-px text-xs cursor-default flex-1 ${
+ rowHeightClass ?? 'h-5'
+ }`}
>
{hasIcon && (
diff --git a/packages/design-system/src/components/table/components/tableBody/bodyRow.tsx b/packages/design-system/src/components/table/components/tableBody/bodyRow.tsx
index ff4ebe5d6..22ff17541 100644
--- a/packages/design-system/src/components/table/components/tableBody/bodyRow.tsx
+++ b/packages/design-system/src/components/table/components/tableBody/bodyRow.tsx
@@ -105,7 +105,7 @@ const BodyRow = ({
style={{
backgroundColor: verticalBarColorHash,
}}
- className="absolute block top-0 bottom-0 left-0 border-l-2 border-emerald-600 dark:border-leaf-green-dark"
+ className="absolute block top-0 bottom-0 left-0 w-1 h-full"
/>
)}
{columns.map(
@@ -124,8 +124,6 @@ const BodyRow = ({
onRowClick={onRowClick}
cell={row[accessorKey]?.value}
width={width || 0}
- isHighlighted={isHighlighted}
- isRowFocused={rowKey === selectedKey}
row={row}
hasIcon={enableBodyCellPrefixIcon}
showIcon={
diff --git a/packages/design-system/src/components/table/useTable/provider.tsx b/packages/design-system/src/components/table/useTable/provider.tsx
index 36e3e9fe4..ffdc4f8b0 100644
--- a/packages/design-system/src/components/table/useTable/provider.tsx
+++ b/packages/design-system/src/components/table/useTable/provider.tsx
@@ -42,6 +42,7 @@ export const TableProvider = ({
conditionalTableRowClassesHandler,
exportTableData,
hasVerticalBar,
+ getVerticalBarColorHash,
isRowSelected,
children,
}: PropsWithChildren
) => {
@@ -167,6 +168,7 @@ export const TableProvider = ({
conditionalTableRowClassesHandler,
exportTableData,
hasVerticalBar,
+ getVerticalBarColorHash,
},
}}
>
diff --git a/packages/explorable-explanations/src/protectedAudience/app.js b/packages/explorable-explanations/src/protectedAudience/app.js
index 5d3b4b544..fe045b860 100644
--- a/packages/explorable-explanations/src/protectedAudience/app.js
+++ b/packages/explorable-explanations/src/protectedAudience/app.js
@@ -64,6 +64,7 @@ const app = {
visitedIndexOrderTracker: -1,
isRevisitingNodeInInteractiveMode: false,
setCurrentSite: () => null,
+ setHighlightedInterestGroup: () => null,
setPlayState: () => null,
usedNextOrPrev: false,
promiseQueue: null,
diff --git a/packages/explorable-explanations/src/protectedAudience/index.js b/packages/explorable-explanations/src/protectedAudience/index.js
index 96cf7ddac..78b48eaeb 100644
--- a/packages/explorable-explanations/src/protectedAudience/index.js
+++ b/packages/explorable-explanations/src/protectedAudience/index.js
@@ -638,6 +638,10 @@ export const interestGroupSketch = (p) => {
app.setCurrentSite = props.setCurrentSite;
}
+ if (props.setHighlightedInterestGroup) {
+ app.setHighlightedInterestGroup = props.setHighlightedInterestGroup;
+ }
+
if (app.setPlayState) {
app.setPlayState = props.setPlayState;
}
diff --git a/packages/explorable-explanations/src/protectedAudience/modules/bubbles.js b/packages/explorable-explanations/src/protectedAudience/modules/bubbles.js
index dcba4d6f4..59bb3e0ac 100644
--- a/packages/explorable-explanations/src/protectedAudience/modules/bubbles.js
+++ b/packages/explorable-explanations/src/protectedAudience/modules/bubbles.js
@@ -374,6 +374,7 @@ bubbles.showExpandedBubbles = () => {
app.openButton.style.display = 'none';
app.minifiedBubbleContainer.classList.toggle('expanded', true);
};
+
bubbles.showMinifiedBubbles = () => {
app.bubbles.minifiedSVG = bubbles.bubbleChart(app.bubbles.positions, {
label: (d) =>
@@ -495,9 +496,13 @@ bubbles.bubbleChart = (
.attr('style', `${!app.bubbles.isExpanded ? 'pointer-events: none;' : ''}`)
.attr('transform', (d) => `translate(${d.x},${d.y})`);
- const eventHandler = (event) => {
+ const eventHandler = (event, d) => {
// eslint-disable-next-line no-console
console.log(event);
+ app.setHighlightedInterestGroup({
+ interestGroupName: titles[d.data].split('\n')[0],
+ color: app.color(groups[d.data]),
+ });
event.stopPropagation();
};
@@ -518,7 +523,10 @@ bubbles.bubbleChart = (
? 'none'
: fill
)
- .on('click', !app.bubbles.isExpanded ? null : eventHandler)
+ .on(
+ 'click',
+ !app.bubbles.isExpanded ? null : (event, d) => eventHandler(event, d)
+ )
.attr('fill-opacity', fillOpacity)
.attr('r', (d) => {
return d.r;
diff --git a/packages/extension/src/view/devtools/components/privateAdvertising/protectedAudience/explorableExplanation/index.tsx b/packages/extension/src/view/devtools/components/privateAdvertising/protectedAudience/explorableExplanation/index.tsx
index 92a3e4797..ac7ea9e82 100644
--- a/packages/extension/src/view/devtools/components/privateAdvertising/protectedAudience/explorableExplanation/index.tsx
+++ b/packages/extension/src/view/devtools/components/privateAdvertising/protectedAudience/explorableExplanation/index.tsx
@@ -202,6 +202,25 @@ const ExplorableExplanation = () => {
return interestGroupsRef.current;
}, [currentSiteData]);
+ const [highlightedInterestGroup, setHighlightedInterestGroup] = useState<{
+ interestGroupName: string;
+ color: string;
+ } | null>(null);
+
+ const timeoutRef = useRef | null>(null);
+
+ useEffect(() => {
+ timeoutRef.current = setTimeout(() => {
+ setHighlightedInterestGroup(null);
+ }, 1500);
+
+ return () => {
+ if (timeoutRef.current) {
+ clearTimeout(timeoutRef.current);
+ }
+ };
+ }, [highlightedInterestGroup]);
+
const tabItems = useMemo(
() => [
{
@@ -210,6 +229,7 @@ const ExplorableExplanation = () => {
Element: IGTable,
props: {
interestGroupDetails: [...(interestGroupData as InterestGroups[])],
+ highlightedInterestGroup,
},
},
},
@@ -251,7 +271,12 @@ const ExplorableExplanation = () => {
},
},
],
- [auctionsData, customAdsAndBidders, interestGroupData]
+ [
+ auctionsData,
+ customAdsAndBidders,
+ highlightedInterestGroup,
+ interestGroupData,
+ ]
);
return (
@@ -259,6 +284,7 @@ const ExplorableExplanation = () => {
);
diff --git a/packages/extension/src/view/devtools/components/privateAdvertising/protectedAudience/explorableExplanation/panel.tsx b/packages/extension/src/view/devtools/components/privateAdvertising/protectedAudience/explorableExplanation/panel.tsx
index 5b113ef46..fc520cda9 100644
--- a/packages/extension/src/view/devtools/components/privateAdvertising/protectedAudience/explorableExplanation/panel.tsx
+++ b/packages/extension/src/view/devtools/components/privateAdvertising/protectedAudience/explorableExplanation/panel.tsx
@@ -48,9 +48,19 @@ declare module 'react' {
interface PanelProps {
setCurrentSite: React.Dispatch>;
currentSiteData: CurrentSiteData | null;
+ setHighlightedInterestGroup: React.Dispatch<
+ React.SetStateAction<{
+ interestGroupName: string;
+ color: string;
+ } | null>
+ >;
}
-const Panel = ({ currentSiteData, setCurrentSite }: PanelProps) => {
+const Panel = ({
+ currentSiteData,
+ setCurrentSite,
+ setHighlightedInterestGroup,
+}: PanelProps) => {
const [play, setPlay] = useState(true);
const [sliderStep, setSliderStep] = useState(1);
const [interactiveMode, _setInteractiveMode] = useState(false);
@@ -279,6 +289,7 @@ const Panel = ({ currentSiteData, setCurrentSite }: PanelProps) => {
speedMultiplier={2 * sliderStep}
setCurrentSite={setCurrentSite}
setPlayState={setPlay}
+ setHighlightedInterestGroup={setHighlightedInterestGroup}
/>
diff --git a/packages/extension/src/view/devtools/components/privateAdvertising/protectedAudience/interestGroups/table.tsx b/packages/extension/src/view/devtools/components/privateAdvertising/protectedAudience/interestGroups/table.tsx
index 32b36c80d..014139dd3 100644
--- a/packages/extension/src/view/devtools/components/privateAdvertising/protectedAudience/interestGroups/table.tsx
+++ b/packages/extension/src/view/devtools/components/privateAdvertising/protectedAudience/interestGroups/table.tsx
@@ -36,9 +36,16 @@ import { prettyPrintJson } from 'pretty-print-json';
interface InterestGroupsProps {
interestGroupDetails: InterestGroupsType[];
+ highlightedInterestGroup?: {
+ interestGroupName: string;
+ color: string;
+ } | null;
}
-const IGTable = ({ interestGroupDetails }: InterestGroupsProps) => {
+const IGTable = ({
+ interestGroupDetails,
+ highlightedInterestGroup,
+}: InterestGroupsProps) => {
const [selectedRow, setSelectedRow] = useState(null);
const [filterData, setFilterData] = useState(false);
@@ -110,6 +117,49 @@ const IGTable = ({ interestGroupDetails }: InterestGroupsProps) => {
[]
);
+ const modifiedInterestGroupDetails = useMemo(() => {
+ if (!highlightedInterestGroup) {
+ return interestGroupDetails;
+ }
+
+ return interestGroupDetails.map((interestGroup) => {
+ const isHighlighted =
+ interestGroup.name === highlightedInterestGroup.interestGroupName;
+
+ return {
+ ...interestGroup,
+ highlighted: isHighlighted,
+ };
+ });
+ }, [interestGroupDetails, highlightedInterestGroup]);
+
+ const hasVerticalBar = useCallback((row: TableRow) => {
+ return Boolean(row.originalData.highlighted);
+ }, []);
+
+ const getVerticalBarColorHash = useCallback(
+ (row: TableRow) => {
+ return row.originalData.highlighted
+ ? highlightedInterestGroup?.color ?? ''
+ : '';
+ },
+ [highlightedInterestGroup?.color]
+ );
+
+ const conditionalTableRowClassesHandler = useCallback(
+ (row: TableRow, isRowFocused: boolean) => {
+ const isHighlighted = row?.originalData?.highlighted;
+ const tableRowClassName = isHighlighted
+ ? isRowFocused
+ ? 'bg-selection-yellow-dark dark:bg-selection-yellow-light text-black transition-colors'
+ : 'bg-royal-blue text-white dark:bg-medium-persian-blue dark:text-chinese-silver'
+ : '';
+
+ return tableRowClassName;
+ },
+ []
+ );
+
const handleChange = useCallback(
(event: React.ChangeEvent) => {
setFilterData(event.target.checked);
@@ -153,8 +203,8 @@ const IGTable = ({ interestGroupDetails }: InterestGroupsProps) => {
event.type === 'leave' || event.type === 'join'
)
}
@@ -162,6 +212,9 @@ const IGTable = ({ interestGroupDetails }: InterestGroupsProps) => {
tableFilterData={tableFilters}
tableSearchKeys={undefined}
tablePersistentSettingsKey="interestGroupsTable"
+ conditionalTableRowClassesHandler={conditionalTableRowClassesHandler}
+ getVerticalBarColorHash={getVerticalBarColorHash}
+ hasVerticalBar={hasVerticalBar}
onRowClick={(row) => {
setSelectedRow(row as InterestGroupsType);
}}