Skip to content

Commit 69d035f

Browse files
committed
feat: remove hydration error, dry nudge style to avoid duplicate code
1 parent b84e263 commit 69d035f

2 files changed

Lines changed: 59 additions & 156 deletions

File tree

packages/app-builder/src/components/Nudge.tsx

Lines changed: 33 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
HoverCardPortal,
55
HoverCardTrigger,
66
} from '@radix-ui/react-hover-card';
7+
import { cva } from 'class-variance-authority';
78
import { type FeatureAccessLevelDto } from 'marble-api/generated/feature-access-api';
89
import { useTranslation } from 'react-i18next';
910
import { match } from 'ts-pattern';
@@ -19,6 +20,35 @@ type NudgeProps = {
1920
collapsed?: boolean;
2021
};
2122

23+
const triggerClassName = cva('flex items-center justify-center text-white ', {
24+
variants: {
25+
kind: {
26+
test: 'bg-purple-65',
27+
restricted: 'bg-purple-82',
28+
missing_configuration: 'bg-yellow-50',
29+
},
30+
collapsed: {
31+
true: 'absolute top-v2-sm right-v2-sm translate-x-[50%] -translate-y-[50%] rounded-full',
32+
false: 'rounded-sm size-6',
33+
},
34+
},
35+
defaultVariants: {
36+
collapsed: false,
37+
},
38+
});
39+
40+
const iconClassName = cva('', {
41+
variants: {
42+
collapsed: {
43+
true: 'size-2.5',
44+
false: 'size-3',
45+
},
46+
},
47+
defaultVariants: {
48+
collapsed: false,
49+
},
50+
});
51+
2252
export const Nudge = ({
2353
content,
2454
link,
@@ -28,109 +58,16 @@ export const Nudge = ({
2858
collapsed = false,
2959
}: NudgeProps) => {
3060
const { t } = useTranslation(['common']);
31-
32-
// When collapsed, render a small circular indicator
33-
if (collapsed) {
34-
return (
35-
<HoverCard>
36-
<HoverCardTrigger
37-
tabIndex={-1}
38-
className={cn(
39-
'absolute -top-0.5 -right-0.5 flex h-1 w-1 items-center justify-center rounded-full',
40-
{ 'bg-purple-65': kind === 'test' },
41-
{ 'bg-purple-82': kind === 'restricted' },
42-
{ 'bg-yellow-50': kind === 'missing_configuration' },
43-
className,
44-
)}
45-
>
46-
<Icon
47-
icon={match<typeof kind, IconName>(kind)
48-
.with('restricted', () => 'lock')
49-
.with('test', () => 'unlock-right')
50-
.with('missing_configuration', () => 'warning')
51-
.exhaustive()}
52-
className="size-2 text-white"
53-
aria-hidden
54-
/>
55-
</HoverCardTrigger>
56-
<HoverCardPortal>
57-
<HoverCardContent
58-
side="right"
59-
align="start"
60-
sideOffset={8}
61-
alignOffset={-8}
62-
className={cn(
63-
'bg-grey-100 z-50 flex w-60 flex-col items-center gap-6 rounded-sm border p-4 pointer-events-auto shadow-lg',
64-
{
65-
'border-purple-82': kind !== 'missing_configuration',
66-
'border-yellow-50': kind === 'missing_configuration',
67-
},
68-
)}
69-
>
70-
<span className="text-m font-bold">
71-
{match<typeof kind, string>(kind)
72-
.with('missing_configuration', () => t('common:missing_configuration_title'))
73-
.otherwise(() => t('common:premium'))}
74-
</span>
75-
<div className="flex w-full flex-col items-center gap-2">
76-
<p className="text-s w-full text-center font-medium">
77-
{match<typeof kind, string>(kind)
78-
.with('missing_configuration', () => t('common:missing_configuration'))
79-
.otherwise(() => content)}
80-
</p>
81-
{link ? (
82-
<a
83-
className="text-s text-purple-65 inline-block w-full text-center hover:underline"
84-
target="_blank"
85-
rel="noreferrer"
86-
href={link}
87-
onClick={(e) => e.stopPropagation()}
88-
>
89-
{t('common:check_on_docs')}
90-
</a>
91-
) : null}
92-
</div>
93-
{kind !== 'missing_configuration' ? (
94-
<a
95-
className={CtaClassName({
96-
variant: 'primary',
97-
color: 'purple',
98-
className: 'mt-4 text-center',
99-
})}
100-
href="https://checkmarble.com/upgrade"
101-
target="_blank"
102-
rel="noreferrer"
103-
onClick={(e) => e.stopPropagation()}
104-
>
105-
{t('common:upgrade')}
106-
</a>
107-
) : null}
108-
</HoverCardContent>
109-
</HoverCardPortal>
110-
</HoverCard>
111-
);
112-
}
113-
114-
// Default expanded state
11561
return (
11662
<HoverCard>
117-
<HoverCardTrigger
118-
tabIndex={-1}
119-
className={cn(
120-
'text-grey-100 flex flex-row items-center justify-center rounded-sm',
121-
{ 'bg-purple-65': kind === 'test' },
122-
{ 'bg-purple-82': kind === 'restricted' },
123-
{ 'bg-yellow-50': kind === 'missing_configuration' },
124-
className,
125-
)}
126-
>
63+
<HoverCardTrigger tabIndex={-1} className={triggerClassName({ kind, collapsed, className })}>
12764
<Icon
12865
icon={match<typeof kind, IconName>(kind)
12966
.with('restricted', () => 'lock')
13067
.with('test', () => 'unlock-right')
13168
.with('missing_configuration', () => 'warning')
13269
.exhaustive()}
133-
className={cn('size-3.5', iconClass)}
70+
className={iconClassName({ collapsed, className: iconClass })}
13471
aria-hidden
13572
/>
13673
</HoverCardTrigger>
@@ -147,6 +84,7 @@ export const Nudge = ({
14784
'border-yellow-50': kind === 'missing_configuration',
14885
},
14986
)}
87+
onClick={(e) => e.stopPropagation()}
15088
>
15189
<span className="text-m font-bold">
15290
{match<typeof kind, string>(kind)
@@ -165,7 +103,6 @@ export const Nudge = ({
165103
target="_blank"
166104
rel="noreferrer"
167105
href={link}
168-
onClick={(e) => e.stopPropagation()}
169106
>
170107
{t('common:check_on_docs')}
171108
</a>
@@ -181,7 +118,6 @@ export const Nudge = ({
181118
href="https://checkmarble.com/upgrade"
182119
target="_blank"
183120
rel="noreferrer"
184-
onClick={(e) => e.stopPropagation()}
185121
>
186122
{t('common:upgrade')}
187123
</a>

packages/app-builder/src/routes/_builder+/_layout.tsx

Lines changed: 26 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -169,79 +169,46 @@ export default function Builder() {
169169
)
170170
.with('restricted', () => (
171171
<div className="text-grey-80 relative flex gap-2 p-2">
172-
<div className="relative">
173-
<Icon icon="analytics" className="size-6 shrink-0" />
174-
{!leftSidebarSharp.value.expanded && (
175-
<Nudge
176-
collapsed
177-
className="size-6"
178-
content={t('navigation:analytics.nudge')}
179-
/>
180-
)}
181-
</div>
172+
<Icon icon="analytics" className="size-6 shrink-0" />
182173
<span className="text-s line-clamp-1 text-start font-medium opacity-0 transition-opacity group-aria-expanded/nav:opacity-100">
183174
{t('navigation:analytics')}
184175
</span>
185-
{leftSidebarSharp.value.expanded && (
186-
<Nudge
187-
className="size-6"
188-
content={t('navigation:analytics.nudge')}
189-
/>
190-
)}
176+
<Nudge
177+
collapsed={!leftSidebarSharp.value.expanded}
178+
className="size-6"
179+
content={t('navigation:analytics.nudge')}
180+
/>
191181
</div>
192182
))
193183
.with('missing_configuration', () => (
194184
<div className="text-grey-80 relative flex gap-2 p-2">
195-
<div className="relative">
196-
<Icon icon="analytics" className="size-6 shrink-0" />
197-
{!leftSidebarSharp.value.expanded && (
198-
<Nudge
199-
collapsed
200-
kind="missing_configuration"
201-
className="size-6"
202-
content={t('navigation:analytics.nudge')}
203-
/>
204-
)}
205-
</div>
185+
<Icon icon="analytics" className="size-6 shrink-0" />
206186
<span className="text-s line-clamp-1 text-start font-medium opacity-0 transition-opacity group-aria-expanded/nav:opacity-100">
207187
{t('navigation:analytics')}
208188
</span>
209-
{leftSidebarSharp.value.expanded && (
210-
<Nudge
211-
kind="missing_configuration"
212-
className="size-6"
213-
content={t('navigation:analytics.nudge')}
214-
/>
215-
)}
189+
<Nudge
190+
collapsed={!leftSidebarSharp.value.expanded}
191+
kind="missing_configuration"
192+
className="size-6"
193+
content={t('navigation:analytics.nudge')}
194+
/>
216195
</div>
217196
))
218197
.with('test', () =>
219198
featuresAccess.isAnalyticsAvailable ? (
220-
<SidebarLink
221-
labelTKey="navigation:analytics"
222-
to={getRoute('/analytics')}
223-
Icon={(props) => (
224-
<div className="relative">
225-
<Icon icon="analytics" {...props} />
226-
{!leftSidebarSharp.value.expanded && (
227-
<Nudge
228-
collapsed
229-
className="size-6"
230-
content={t('navigation:analytics.nudge')}
231-
kind="test"
232-
/>
233-
)}
234-
</div>
235-
)}
236-
>
237-
{leftSidebarSharp.value.expanded && (
238-
<Nudge
239-
className="size-6"
240-
content={t('navigation:analytics.nudge')}
241-
kind="test"
242-
/>
243-
)}
244-
</SidebarLink>
199+
<div className="relative">
200+
<SidebarLink
201+
labelTKey="navigation:analytics"
202+
to={getRoute('/analytics')}
203+
Icon={(props) => <Icon icon="analytics" {...props} />}
204+
/>
205+
<Nudge
206+
collapsed={!leftSidebarSharp.value.expanded}
207+
className="size-6"
208+
content={t('navigation:analytics.nudge')}
209+
kind="test"
210+
/>
211+
</div>
245212
) : null,
246213
)
247214
.exhaustive()}

0 commit comments

Comments
 (0)