diff --git a/packages/desktop-client/package.json b/packages/desktop-client/package.json index ffb902de6ab198797a18537d6318659d304b026e..b160ffc21a39bf3996f3aef48d23042869b796d4 100644 --- a/packages/desktop-client/package.json +++ b/packages/desktop-client/package.json @@ -6,6 +6,7 @@ "build" ], "devDependencies": { + "@fontsource/redacted-script": "^5.0.21", "@juggle/resize-observer": "^3.4.0", "@playwright/test": "1.41.1", "@rollup/plugin-inject": "^5.0.5", diff --git a/packages/desktop-client/src/components/PrivacyFilter.tsx b/packages/desktop-client/src/components/PrivacyFilter.tsx index 5a455dc60dd332c013ed8f1f424e96162a3c9ebd..f8d83249145818dfebd64dc38bf847e2498d3f0e 100644 --- a/packages/desktop-client/src/components/PrivacyFilter.tsx +++ b/packages/desktop-client/src/components/PrivacyFilter.tsx @@ -1,12 +1,12 @@ // @ts-strict-ignore import React, { - useState, - useCallback, Children, type ComponentPropsWithRef, type ReactNode, } from 'react'; +import { css } from 'glamor'; + import { usePrivacyMode } from '../hooks/usePrivacyMode'; import { useResponsive } from '../ResponsiveProvider'; @@ -44,11 +44,9 @@ export function ConditionalPrivacyFilter({ type PrivacyFilterProps = ComponentPropsWithRef<typeof View> & { activationFilters?: (boolean | (() => boolean))[]; - blurIntensity?: number; }; export function PrivacyFilter({ activationFilters, - blurIntensity, children, ...props }: PrivacyFilterProps) { @@ -63,46 +61,70 @@ export function PrivacyFilter({ typeof value === 'boolean' ? value : value(), )); - const blurAmount = blurIntensity != null ? `${blurIntensity}px` : '3px'; - return !activate ? ( <>{Children.toArray(children)}</> ) : ( - <BlurredOverlay blurIntensity={blurAmount} {...props}> - {children} - </BlurredOverlay> + <PrivacyOverlay {...props}>{children}</PrivacyOverlay> ); } -function BlurredOverlay({ blurIntensity, children, ...props }) { - const [hovered, setHovered] = useState(false); - const onHover = useCallback(() => setHovered(true), [setHovered]); - const onHoverEnd = useCallback(() => setHovered(false), [setHovered]); - - const blurStyle = { - ...(!hovered && { - filter: `blur(${blurIntensity})`, - WebkitFilter: `blur(${blurIntensity})`, - // To fix blur performance issue in Safari. - // https://graffino.com/til/CjT2jrcLHP-how-to-fix-filter-blur-performance-issue-in-safari - transform: `translate3d(0, 0, 0)`, - }), - }; - +function PrivacyOverlay({ children, ...props }) { const { style, ...restProps } = props; return ( <View - style={{ - display: style?.display ? style.display : 'inline-flex', - ...blurStyle, - ...style, - }} - onPointerEnter={onHover} - onPointerLeave={onHoverEnd} + className={`${css( + [ + { + display: 'inline-flex', + flexGrow: 1, + position: 'relative', + ' > div:first-child': { + opacity: 0, + }, + ' > div:nth-child(2)': { + display: 'flex', + }, + '&:hover': { + ' > div:first-child': { + opacity: 1, + }, + ' > div:nth-child(2)': { + display: 'none', + }, + }, + }, + ], + style, + )}`} {...restProps} > - {children} + <div + className={`${css([ + { + display: 'flex', + flexGrow: 1, + }, + ])}`} + > + {children} + </div> + + <div + aria-hidden="true" + className={`${css({ + flexDirection: 'column', + fontFamily: 'Redacted Script', + height: '100%', + inset: 0, + justifyContent: 'center', + pointerEvents: 'none', + position: 'absolute', + width: '100%', + })}`} + > + {children} + </div> </View> ); } diff --git a/packages/desktop-client/src/components/budget/envelope/EnvelopeBudgetComponents.tsx b/packages/desktop-client/src/components/budget/envelope/EnvelopeBudgetComponents.tsx index 68599d33ad6d016d7ae0ce39a64979c989b52d4d..449c13a4a3c3c328b6027a4f680867e164d12599 100644 --- a/packages/desktop-client/src/components/budget/envelope/EnvelopeBudgetComponents.tsx +++ b/packages/desktop-client/src/components/budget/envelope/EnvelopeBudgetComponents.tsx @@ -169,11 +169,6 @@ export const ExpenseGroupMonth = memo(function ExpenseGroupMonth({ valueProps={{ binding: envelopeBudget.groupBalance(id), type: 'financial', - privacyFilter: { - style: { - paddingRight: styles.monthRightPadding, - }, - }, }} /> </View> @@ -431,11 +426,6 @@ export function IncomeGroupMonth({ month }: IncomeGroupMonthProps) { valueProps={{ binding: envelopeBudget.groupIncomeReceived, type: 'financial', - privacyFilter: { - style: { - paddingRight: styles.monthRightPadding, - }, - }, }} /> </View> diff --git a/packages/desktop-client/src/components/budget/envelope/budgetsummary/ToBudgetAmount.tsx b/packages/desktop-client/src/components/budget/envelope/budgetsummary/ToBudgetAmount.tsx index a03f2560d111c6c4dcb57f7606c6080683e01e78..04dafd37e45319a6be4d8f324e7428ac02795717 100644 --- a/packages/desktop-client/src/components/budget/envelope/budgetsummary/ToBudgetAmount.tsx +++ b/packages/desktop-client/src/components/budget/envelope/budgetsummary/ToBudgetAmount.tsx @@ -64,7 +64,11 @@ export function ToBudgetAmount({ offset={3} triggerProps={{ isDisabled: isTotalsListTooltipDisabled }} > - <PrivacyFilter blurIntensity={7}> + <PrivacyFilter + style={{ + textAlign: 'center', + }} + > <Block onClick={onClick} data-cellname={sheetName} diff --git a/packages/desktop-client/src/components/budget/tracking/TrackingBudgetComponents.tsx b/packages/desktop-client/src/components/budget/tracking/TrackingBudgetComponents.tsx index c241bf876dc019cbf7688c65035dfdd1ee04f8da..b9bb66eda337983f6d6d991001a02ff4c85c853b 100644 --- a/packages/desktop-client/src/components/budget/tracking/TrackingBudgetComponents.tsx +++ b/packages/desktop-client/src/components/budget/tracking/TrackingBudgetComponents.tsx @@ -178,11 +178,6 @@ export const GroupMonth = memo(function GroupMonth({ valueProps={{ binding: trackingBudget.groupBalance(id), type: 'financial', - privacyFilter: { - style: { - paddingRight: styles.monthRightPadding, - }, - }, }} /> )} diff --git a/packages/desktop-client/src/components/budget/tracking/budgetsummary/Saved.tsx b/packages/desktop-client/src/components/budget/tracking/budgetsummary/Saved.tsx index 5fdb9e1c4075a03172e751ac1e3a63b7720c8c21..dfadfa9436adaa0ee5e0c514943d72d82ea47d57 100644 --- a/packages/desktop-client/src/components/budget/tracking/budgetsummary/Saved.tsx +++ b/packages/desktop-client/src/components/budget/tracking/budgetsummary/Saved.tsx @@ -85,9 +85,7 @@ export function Saved({ projected, style }: SavedProps) { }, ])}`} > - <PrivacyFilter blurIntensity={7}> - {format(saved, 'financial')} - </PrivacyFilter> + <PrivacyFilter>{format(saved, 'financial')}</PrivacyFilter> </View> </Tooltip> </View> diff --git a/packages/desktop-client/src/components/reports/ReportSummary.tsx b/packages/desktop-client/src/components/reports/ReportSummary.tsx index 88968e67a0a668f416a95cfa0b80e2a351ac6b05..137ea927095983e98c38aa303d7db2a28a5ab531 100644 --- a/packages/desktop-client/src/components/reports/ReportSummary.tsx +++ b/packages/desktop-client/src/components/reports/ReportSummary.tsx @@ -117,9 +117,7 @@ export function ReportSummary({ fontWeight: 800, }} > - <PrivacyFilter blurIntensity={7}> - {amountToCurrency(data[balanceTypeOp])} - </PrivacyFilter> + <PrivacyFilter>{amountToCurrency(data[balanceTypeOp])}</PrivacyFilter> </Text> <Text style={{ fontWeight: 600 }}>For this time period</Text> </View> @@ -154,7 +152,7 @@ export function ReportSummary({ fontWeight: 800, }} > - <PrivacyFilter blurIntensity={7}> + <PrivacyFilter> {!isNaN(average) && integerToCurrency(Math.round(average))} </PrivacyFilter> </Text> diff --git a/packages/desktop-client/src/components/reports/reports/CustomReport.tsx b/packages/desktop-client/src/components/reports/reports/CustomReport.tsx index 53ebf20563330b5f062f7f63c59389942fb95e7a..346983de072deac376e445b249e5d4c73a14356b 100644 --- a/packages/desktop-client/src/components/reports/reports/CustomReport.tsx +++ b/packages/desktop-client/src/components/reports/reports/CustomReport.tsx @@ -804,7 +804,7 @@ export function CustomReport() { left={<Block>{balanceType}:</Block>} right={ <Text> - <PrivacyFilter blurIntensity={5}> + <PrivacyFilter> {amountToCurrency(data[balanceTypeOp])} </PrivacyFilter> </Text> diff --git a/packages/desktop-client/src/components/reports/reports/NetWorth.jsx b/packages/desktop-client/src/components/reports/reports/NetWorth.jsx index 31a0abace8c7a507c7d68bde53c1615d441cedc1..7f58ab8d04124e88303f031049a61244f6b488de 100644 --- a/packages/desktop-client/src/components/reports/reports/NetWorth.jsx +++ b/packages/desktop-client/src/components/reports/reports/NetWorth.jsx @@ -195,9 +195,7 @@ function NetWorthInner({ widget }) { <View style={{ ...styles.largeText, fontWeight: 400, marginBottom: 5 }} > - <PrivacyFilter blurIntensity={5}> - {integerToCurrency(data.netWorth)} - </PrivacyFilter> + <PrivacyFilter>{integerToCurrency(data.netWorth)}</PrivacyFilter> </View> <PrivacyFilter> <Change amount={data.totalChange} /> diff --git a/packages/desktop-client/src/components/reports/reports/Spending.tsx b/packages/desktop-client/src/components/reports/reports/Spending.tsx index f8d44b93d3fe9d661ce59500559932b1cf448989..7efc495e6b6fa3af48b351f907771f8941b5679e 100644 --- a/packages/desktop-client/src/components/reports/reports/Spending.tsx +++ b/packages/desktop-client/src/components/reports/reports/Spending.tsx @@ -474,7 +474,7 @@ function SpendingInternal({ widget }: SpendingInternalProps) { } right={ <Text style={{ fontWeight: 600 }}> - <PrivacyFilter blurIntensity={5}> + <PrivacyFilter> {amountToCurrency( Math.abs(data.intervalData[todayDay].compare), )} @@ -494,7 +494,7 @@ function SpendingInternal({ widget }: SpendingInternalProps) { } right={ <Text style={{ fontWeight: 600 }}> - <PrivacyFilter blurIntensity={5}> + <PrivacyFilter> {amountToCurrency( Math.abs(data.intervalData[todayDay].compareTo), )} @@ -515,7 +515,7 @@ function SpendingInternal({ widget }: SpendingInternalProps) { } right={ <Text style={{ fontWeight: 600 }}> - <PrivacyFilter blurIntensity={5}> + <PrivacyFilter> {amountToCurrency( Math.abs(data.intervalData[todayDay].budget), )} @@ -535,7 +535,7 @@ function SpendingInternal({ widget }: SpendingInternalProps) { } right={ <Text style={{ fontWeight: 600 }}> - <PrivacyFilter blurIntensity={5}> + <PrivacyFilter> {amountToCurrency( Math.abs(data.intervalData[todayDay].average), )} diff --git a/packages/desktop-client/src/components/table.tsx b/packages/desktop-client/src/components/table.tsx index 60f38a0ee7231cbf7f998c92e129c1f609e6a08f..655c8f954e9524dde33b8dfb36b97a0707e8cc29 100644 --- a/packages/desktop-client/src/components/table.tsx +++ b/packages/desktop-client/src/components/table.tsx @@ -197,11 +197,6 @@ export function Cell({ privacyFilter={mergeConditionalPrivacyFilterProps( { activationFilters: [!focused, !exposed], - style: { - position: 'absolute', - width: '100%', - height: '100%', - }, }, privacyFilter, )} diff --git a/packages/desktop-client/src/fonts.scss b/packages/desktop-client/src/fonts.scss index dba3274d48424ff073450c0ed085561b325c69db..cd47daca1a07b087354ac5d1421c81e255cafbc5 100644 --- a/packages/desktop-client/src/fonts.scss +++ b/packages/desktop-client/src/fonts.scss @@ -2,3 +2,5 @@ $inter-font-path: '../../../node_modules/inter-ui/Inter (web)' ); @include variable.default; + +@import "@fontsource/redacted-script"; diff --git a/upcoming-release-notes/3377.md b/upcoming-release-notes/3377.md new file mode 100644 index 0000000000000000000000000000000000000000..2ebd4574f94aed6afd24ed72719b3b0fb5b52563 --- /dev/null +++ b/upcoming-release-notes/3377.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [olets] +--- + +Privacy mode: instead of blurring, use an illegible font (#3376) diff --git a/yarn.lock b/yarn.lock index 09207fbfe1d583f079af847748074f7aad0a2e11..11aae8c7785845ee21cd9c4952db47f3371a8f5e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -59,6 +59,7 @@ __metadata: version: 0.0.0-use.local resolution: "@actual-app/web@workspace:packages/desktop-client" dependencies: + "@fontsource/redacted-script": "npm:^5.0.21" "@juggle/resize-observer": "npm:^3.4.0" "@playwright/test": "npm:1.41.1" "@rollup/plugin-inject": "npm:^5.0.5" @@ -1846,6 +1847,13 @@ __metadata: languageName: node linkType: hard +"@fontsource/redacted-script@npm:^5.0.21": + version: 5.0.21 + resolution: "@fontsource/redacted-script@npm:5.0.21" + checksum: 10/93f506c9e8df827ab1872d433a09079c592f3a20a1c36b9a168e68377967d3d1d282fffd51bee973c2ecb253316ff4641d244f8f05242e4aa968a1eb14d065eb + languageName: node + linkType: hard + "@formatjs/ecma402-abstract@npm:1.15.0": version: 1.15.0 resolution: "@formatjs/ecma402-abstract@npm:1.15.0"