mirror of
https://github.com/documenso/documenso.git
synced 2026-07-26 18:04:55 +10:00
refactor: avoid recipient color duplication (#2355)
This commit is contained in:
@@ -16,7 +16,7 @@ import { type TFieldMetaSchema, ZFieldMetaSchema } from '@documenso/lib/types/fi
|
|||||||
import { nanoid } from '@documenso/lib/universal/id';
|
import { nanoid } from '@documenso/lib/universal/id';
|
||||||
import { ADVANCED_FIELD_TYPES_WITH_OPTIONAL_SETTING } from '@documenso/lib/utils/advanced-fields-helpers';
|
import { ADVANCED_FIELD_TYPES_WITH_OPTIONAL_SETTING } from '@documenso/lib/utils/advanced-fields-helpers';
|
||||||
import { getDocumentDataUrlForPdfViewer } from '@documenso/lib/utils/envelope-download';
|
import { getDocumentDataUrlForPdfViewer } from '@documenso/lib/utils/envelope-download';
|
||||||
import { useRecipientColors } from '@documenso/ui/lib/recipient-colors';
|
import { getRecipientColorStyles } from '@documenso/ui/lib/recipient-colors';
|
||||||
import { cn } from '@documenso/ui/lib/utils';
|
import { cn } from '@documenso/ui/lib/utils';
|
||||||
import { Button } from '@documenso/ui/primitives/button';
|
import { Button } from '@documenso/ui/primitives/button';
|
||||||
import { FieldItem } from '@documenso/ui/primitives/document-flow/field-item';
|
import { FieldItem } from '@documenso/ui/primitives/document-flow/field-item';
|
||||||
@@ -155,9 +155,7 @@ export const ConfigureFieldsView = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const selectedRecipientIndex = recipients.findIndex((r) => r.id === selectedRecipient?.id);
|
const selectedRecipientIndex = recipients.findIndex((r) => r.id === selectedRecipient?.id);
|
||||||
const selectedRecipientStyles = useRecipientColors(
|
const selectedRecipientStyles = getRecipientColorStyles(selectedRecipientIndex);
|
||||||
selectedRecipientIndex === -1 ? 0 : selectedRecipientIndex,
|
|
||||||
);
|
|
||||||
|
|
||||||
const form = useForm<TConfigureFieldsFormSchema>({
|
const form = useForm<TConfigureFieldsFormSchema>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
|
|||||||
+11
-13
@@ -9,7 +9,7 @@ import { type TRecipientActionAuth } from '@documenso/lib/types/document-auth';
|
|||||||
import { ZFieldMetaSchema } from '@documenso/lib/types/field-meta';
|
import { ZFieldMetaSchema } from '@documenso/lib/types/field-meta';
|
||||||
import type { FieldWithSignature } from '@documenso/prisma/types/field-with-signature';
|
import type { FieldWithSignature } from '@documenso/prisma/types/field-with-signature';
|
||||||
import { FieldRootContainer } from '@documenso/ui/components/field/field';
|
import { FieldRootContainer } from '@documenso/ui/components/field/field';
|
||||||
import { RECIPIENT_COLOR_STYLES } from '@documenso/ui/lib/recipient-colors';
|
import { getRecipientColorStyles } from '@documenso/ui/lib/recipient-colors';
|
||||||
import { cn } from '@documenso/ui/lib/utils';
|
import { cn } from '@documenso/ui/lib/utils';
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@documenso/ui/primitives/tooltip';
|
import { Tooltip, TooltipContent, TooltipTrigger } from '@documenso/ui/primitives/tooltip';
|
||||||
|
|
||||||
@@ -131,18 +131,16 @@ export const DocumentSigningFieldContainer = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<FieldRootContainer
|
<FieldRootContainer
|
||||||
color={
|
color={getRecipientColorStyles(field.fieldMeta?.readOnly ? 'readOnly' : 0)}
|
||||||
field.fieldMeta?.readOnly ? RECIPIENT_COLOR_STYLES.readOnly : RECIPIENT_COLOR_STYLES.green
|
field={field}
|
||||||
}
|
>
|
||||||
field={field}
|
{!field.inserted && !loading && !readOnlyField && (
|
||||||
>
|
<button
|
||||||
{!field.inserted && !loading && !readOnlyField && (
|
type="submit"
|
||||||
<button
|
className="absolute inset-0 z-10 h-full w-full rounded-[2px]"
|
||||||
type="submit"
|
onClick={async () => handleInsertField()}
|
||||||
className="absolute inset-0 z-10 h-full w-full rounded-[2px]"
|
/>
|
||||||
onClick={async () => handleInsertField()}
|
)}
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{type === 'Checkbox' && field.inserted && !loading && !readOnlyField && (
|
{type === 'Checkbox' && field.inserted && !loading && !readOnlyField && (
|
||||||
<button
|
<button
|
||||||
|
|||||||
+8
-14
@@ -23,7 +23,7 @@ import { FIELD_META_DEFAULT_VALUES } from '@documenso/lib/types/field-meta';
|
|||||||
import { nanoid } from '@documenso/lib/universal/id';
|
import { nanoid } from '@documenso/lib/universal/id';
|
||||||
import { canRecipientFieldsBeModified } from '@documenso/lib/utils/recipients';
|
import { canRecipientFieldsBeModified } from '@documenso/lib/utils/recipients';
|
||||||
import { SignatureIcon } from '@documenso/ui/icons/signature';
|
import { SignatureIcon } from '@documenso/ui/icons/signature';
|
||||||
import { RECIPIENT_COLOR_STYLES } from '@documenso/ui/lib/recipient-colors';
|
import { getRecipientColorStyles } from '@documenso/ui/lib/recipient-colors';
|
||||||
import { cn } from '@documenso/ui/lib/utils';
|
import { cn } from '@documenso/ui/lib/utils';
|
||||||
import { FRIENDLY_FIELD_TYPE } from '@documenso/ui/primitives/document-flow/types';
|
import { FRIENDLY_FIELD_TYPE } from '@documenso/ui/primitives/document-flow/types';
|
||||||
|
|
||||||
@@ -253,9 +253,10 @@ export const EnvelopeEditorFieldDragDrop = ({
|
|||||||
};
|
};
|
||||||
}, [onMouseClick, onMouseMove, selectedField]);
|
}, [onMouseClick, onMouseMove, selectedField]);
|
||||||
|
|
||||||
const selectedRecipientColor = useMemo(() => {
|
const selectedRecipientStyles = useMemo(
|
||||||
return selectedRecipientId ? getRecipientColorKey(selectedRecipientId) : 'green';
|
() => getRecipientColorStyles(getRecipientColorKey(selectedRecipientId ?? -1)),
|
||||||
}, [selectedRecipientId, getRecipientColorKey]);
|
[selectedRecipientId, getRecipientColorKey],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -270,21 +271,14 @@ export const EnvelopeEditorFieldDragDrop = ({
|
|||||||
data-selected={selectedField === field.type ? true : undefined}
|
data-selected={selectedField === field.type ? true : undefined}
|
||||||
className={cn(
|
className={cn(
|
||||||
'group flex h-12 cursor-pointer items-center justify-center rounded-lg border border-border px-4 transition-colors',
|
'group flex h-12 cursor-pointer items-center justify-center rounded-lg border border-border px-4 transition-colors',
|
||||||
RECIPIENT_COLOR_STYLES[selectedRecipientColor].fieldButton,
|
selectedRecipientStyles.fieldButton,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<p
|
<p
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center justify-center gap-x-1.5 font-noto text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
'flex items-center justify-center gap-x-1.5 font-noto text-sm font-normal text-muted-foreground group-data-[selected]:text-foreground',
|
||||||
field.className,
|
field.className,
|
||||||
{
|
selectedRecipientStyles.fieldButtonText,
|
||||||
'group-hover:text-recipient-green': selectedRecipientColor === 'green',
|
|
||||||
'group-hover:text-recipient-blue': selectedRecipientColor === 'blue',
|
|
||||||
'group-hover:text-recipient-purple': selectedRecipientColor === 'purple',
|
|
||||||
'group-hover:text-recipient-orange': selectedRecipientColor === 'orange',
|
|
||||||
'group-hover:text-recipient-yellow': selectedRecipientColor === 'yellow',
|
|
||||||
'group-hover:text-recipient-pink': selectedRecipientColor === 'pink',
|
|
||||||
},
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{field.type !== FieldType.SIGNATURE && <field.icon className="h-4 w-4" />}
|
{field.type !== FieldType.SIGNATURE && <field.icon className="h-4 w-4" />}
|
||||||
@@ -298,7 +292,7 @@ export const EnvelopeEditorFieldDragDrop = ({
|
|||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'dark:text-muted-background pointer-events-none fixed z-50 flex cursor-pointer flex-col items-center justify-center rounded-[2px] bg-white font-noto text-muted-foreground ring-2 transition duration-200 [container-type:size]',
|
'dark:text-muted-background pointer-events-none fixed z-50 flex cursor-pointer flex-col items-center justify-center rounded-[2px] bg-white font-noto text-muted-foreground ring-2 transition duration-200 [container-type:size]',
|
||||||
RECIPIENT_COLOR_STYLES[selectedRecipientColor].base,
|
selectedRecipientStyles.base,
|
||||||
selectedField === FieldType.SIGNATURE && 'font-signature',
|
selectedField === FieldType.SIGNATURE && 'font-signature',
|
||||||
{
|
{
|
||||||
'-rotate-6 scale-90 opacity-50 dark:bg-black/20': !isFieldWithinBounds,
|
'-rotate-6 scale-90 opacity-50 dark:bg-black/20': !isFieldWithinBounds,
|
||||||
|
|||||||
@@ -59,12 +59,8 @@ export const EnvelopeRecipientSelector = ({
|
|||||||
role="combobox"
|
role="combobox"
|
||||||
className={cn(
|
className={cn(
|
||||||
'justify-between bg-background font-normal text-muted-foreground hover:text-foreground',
|
'justify-between bg-background font-normal text-muted-foreground hover:text-foreground',
|
||||||
getRecipientColorStyles(
|
getRecipientColorStyles(recipients.findIndex((r) => r.id === selectedRecipient?.id))
|
||||||
Math.max(
|
.comboBoxTrigger,
|
||||||
recipients.findIndex((r) => r.id === selectedRecipient?.id),
|
|
||||||
0,
|
|
||||||
),
|
|
||||||
).comboxBoxTrigger,
|
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -197,12 +193,8 @@ export const EnvelopeRecipientSelectorCommand = ({
|
|||||||
key={recipient.id}
|
key={recipient.id}
|
||||||
className={cn(
|
className={cn(
|
||||||
'px-2 last:mb-1 [&:not(:first-child)]:mt-1',
|
'px-2 last:mb-1 [&:not(:first-child)]:mt-1',
|
||||||
getRecipientColorStyles(
|
getRecipientColorStyles(recipients.findIndex((r) => r.id === recipient.id))
|
||||||
Math.max(
|
.comboBoxItem,
|
||||||
recipients.findIndex((r) => r.id === recipient.id),
|
|
||||||
0,
|
|
||||||
),
|
|
||||||
).comboxBoxItem,
|
|
||||||
{
|
{
|
||||||
'text-muted-foreground': recipient.sendStatus === SendStatus.SENT,
|
'text-muted-foreground': recipient.sendStatus === SendStatus.SENT,
|
||||||
'cursor-not-allowed': isRecipientDisabled(recipient.id),
|
'cursor-not-allowed': isRecipientDisabled(recipient.id),
|
||||||
|
|||||||
+5
-8
@@ -32,7 +32,6 @@ import { extractInitials } from '@documenso/lib/utils/recipient-formatter';
|
|||||||
import type { TSignEnvelopeFieldValue } from '@documenso/trpc/server/envelope-router/sign-envelope-field.types';
|
import type { TSignEnvelopeFieldValue } from '@documenso/trpc/server/envelope-router/sign-envelope-field.types';
|
||||||
import { EnvelopeRecipientFieldTooltip } from '@documenso/ui/components/document/envelope-recipient-field-tooltip';
|
import { EnvelopeRecipientFieldTooltip } from '@documenso/ui/components/document/envelope-recipient-field-tooltip';
|
||||||
import { EnvelopeFieldToolTip } from '@documenso/ui/components/field/envelope-field-tooltip';
|
import { EnvelopeFieldToolTip } from '@documenso/ui/components/field/envelope-field-tooltip';
|
||||||
import type { TRecipientColor } from '@documenso/ui/lib/recipient-colors';
|
|
||||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||||
|
|
||||||
import { useEmbedSigningContext } from '~/components/embed/embed-signing-context';
|
import { useEmbedSigningContext } from '~/components/embed/embed-signing-context';
|
||||||
@@ -139,13 +138,11 @@ export const EnvelopeSignerPageRenderer = ({ pageData }: { pageData: PageRenderD
|
|||||||
|
|
||||||
const fieldToRender = ZFullFieldSchema.parse(unparsedField);
|
const fieldToRender = ZFullFieldSchema.parse(unparsedField);
|
||||||
|
|
||||||
let color: TRecipientColor = 'green';
|
const color = fieldToRender.fieldMeta?.readOnly
|
||||||
|
? 'readOnly'
|
||||||
if (fieldToRender.fieldMeta?.readOnly) {
|
: showPendingFieldTooltip && isFieldUnsignedAndRequired(fieldToRender)
|
||||||
color = 'readOnly';
|
? 'orange'
|
||||||
} else if (showPendingFieldTooltip && isFieldUnsignedAndRequired(fieldToRender)) {
|
: 'green';
|
||||||
color = 'orange';
|
|
||||||
}
|
|
||||||
|
|
||||||
const { fieldGroup } = renderField({
|
const { fieldGroup } = renderField({
|
||||||
scale,
|
scale,
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
const baseConfig = require('@documenso/tailwind-config');
|
const baseConfig = require('@documenso/ui/tailwind.config.cjs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
...baseConfig,
|
presets: [baseConfig],
|
||||||
content: [
|
content: [
|
||||||
...baseConfig.content,
|
|
||||||
'./app/**/*.{ts,tsx}',
|
'./app/**/*.{ts,tsx}',
|
||||||
`${path.join(require.resolve('@documenso/ui'), '..')}/components/**/*.{ts,tsx}`,
|
`${path.join(require.resolve('@documenso/ui'), '..')}/components/**/*.{ts,tsx}`,
|
||||||
`${path.join(require.resolve('@documenso/ui'), '..')}/icons/**/*.{ts,tsx}`,
|
`${path.join(require.resolve('@documenso/ui'), '..')}/icons/**/*.{ts,tsx}`,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import type { TSetEnvelopeFieldsResponse } from '@documenso/trpc/server/envelope
|
|||||||
import type { TSetEnvelopeRecipientsRequest } from '@documenso/trpc/server/envelope-router/set-envelope-recipients.types';
|
import type { TSetEnvelopeRecipientsRequest } from '@documenso/trpc/server/envelope-router/set-envelope-recipients.types';
|
||||||
import type { TUpdateEnvelopeRequest } from '@documenso/trpc/server/envelope-router/update-envelope.types';
|
import type { TUpdateEnvelopeRequest } from '@documenso/trpc/server/envelope-router/update-envelope.types';
|
||||||
import type { TRecipientColor } from '@documenso/ui/lib/recipient-colors';
|
import type { TRecipientColor } from '@documenso/ui/lib/recipient-colors';
|
||||||
import { AVAILABLE_RECIPIENT_COLORS } from '@documenso/ui/lib/recipient-colors';
|
import { getRecipientColor } from '@documenso/ui/lib/recipient-colors';
|
||||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||||
|
|
||||||
import type { TDocumentEmailSettings } from '../../types/document-email';
|
import type { TDocumentEmailSettings } from '../../types/document-email';
|
||||||
@@ -346,15 +346,8 @@ export const EnvelopeEditorProvider = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getRecipientColorKey = useCallback(
|
const getRecipientColorKey = useCallback(
|
||||||
(recipientId: number) => {
|
(recipientId: number) =>
|
||||||
const recipientIndex = envelope.recipients.findIndex(
|
getRecipientColor(envelope.recipients.findIndex((r) => r.id === recipientId)),
|
||||||
(recipient) => recipient.id === recipientId,
|
|
||||||
);
|
|
||||||
|
|
||||||
return AVAILABLE_RECIPIENT_COLORS[
|
|
||||||
Math.max(recipientIndex, 0) % AVAILABLE_RECIPIENT_COLORS.length
|
|
||||||
];
|
|
||||||
},
|
|
||||||
[envelope.recipients],
|
[envelope.recipients],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { type Field, type Recipient } from '@prisma/client';
|
|||||||
import type { DocumentDataVersion } from '@documenso/lib/types/document';
|
import type { DocumentDataVersion } from '@documenso/lib/types/document';
|
||||||
import { getDocumentDataUrl } from '@documenso/lib/utils/envelope-download';
|
import { getDocumentDataUrl } from '@documenso/lib/utils/envelope-download';
|
||||||
import type { TRecipientColor } from '@documenso/ui/lib/recipient-colors';
|
import type { TRecipientColor } from '@documenso/ui/lib/recipient-colors';
|
||||||
import { AVAILABLE_RECIPIENT_COLORS } from '@documenso/ui/lib/recipient-colors';
|
import { getRecipientColor } from '@documenso/ui/lib/recipient-colors';
|
||||||
|
|
||||||
import type { TEnvelope } from '../../types/envelope';
|
import type { TEnvelope } from '../../types/envelope';
|
||||||
import type { FieldRenderMode } from '../../universal/field-renderer/render-field';
|
import type { FieldRenderMode } from '../../universal/field-renderer/render-field';
|
||||||
@@ -198,13 +198,7 @@ export const EnvelopeRenderProvider = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const getRecipientColorKey = useCallback(
|
const getRecipientColorKey = useCallback(
|
||||||
(recipientId: number) => {
|
(recipientId: number) => getRecipientColor(recipientIds.findIndex((id) => id === recipientId)),
|
||||||
const recipientIndex = recipientIds.findIndex((id) => id === recipientId);
|
|
||||||
|
|
||||||
return AVAILABLE_RECIPIENT_COLORS[
|
|
||||||
Math.max(recipientIndex, 0) % AVAILABLE_RECIPIENT_COLORS.length
|
|
||||||
];
|
|
||||||
},
|
|
||||||
[recipientIds],
|
[recipientIds],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import Konva from 'konva';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
DEFAULT_RECT_BACKGROUND,
|
DEFAULT_RECT_BACKGROUND,
|
||||||
RECIPIENT_COLOR_STYLES,
|
getRecipientColorStyles,
|
||||||
} from '@documenso/ui/lib/recipient-colors';
|
} from '@documenso/ui/lib/recipient-colors';
|
||||||
|
|
||||||
import type { FieldToRender, RenderFieldElementOptions } from './field-renderer';
|
import type { FieldToRender, RenderFieldElementOptions } from './field-renderer';
|
||||||
@@ -70,7 +70,7 @@ export const upsertFieldRect = (
|
|||||||
width: fieldWidth,
|
width: fieldWidth,
|
||||||
height: fieldHeight,
|
height: fieldHeight,
|
||||||
fill: DEFAULT_RECT_BACKGROUND,
|
fill: DEFAULT_RECT_BACKGROUND,
|
||||||
stroke: color ? RECIPIENT_COLOR_STYLES[color].baseRing : '#e5e7eb',
|
stroke: color ? getRecipientColorStyles(color).baseRing : '#e5e7eb',
|
||||||
strokeWidth: 2,
|
strokeWidth: 2,
|
||||||
cornerRadius: 2,
|
cornerRadius: 2,
|
||||||
strokeScaleEnabled: false,
|
strokeScaleEnabled: false,
|
||||||
@@ -150,7 +150,7 @@ export const createFieldHoverInteraction = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hoverColor = RECIPIENT_COLOR_STYLES[options.color].baseRingHover;
|
const hoverColor = getRecipientColorStyles(options.color).baseRingHover;
|
||||||
|
|
||||||
fieldGroup.on('mouseover', () => {
|
fieldGroup.on('mouseover', () => {
|
||||||
const layer = fieldRect.getLayer();
|
const layer = fieldRect.getLayer();
|
||||||
|
|||||||
@@ -110,10 +110,7 @@ export const DocumentReadOnlyFields = ({
|
|||||||
color={
|
color={
|
||||||
showRecipientColors
|
showRecipientColors
|
||||||
? getRecipientColorStyles(
|
? getRecipientColorStyles(
|
||||||
Math.max(
|
recipientIds.findIndex((id) => id === field.recipientId),
|
||||||
recipientIds.findIndex((id) => id === field.recipientId),
|
|
||||||
0,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
// !: We declare all of our classes here since TailwindCSS will remove any unused CSS classes,
|
import { colord } from 'colord';
|
||||||
// !: therefore doing this at runtime is not possible without whitelisting a set of classnames.
|
import { once } from 'remeda';
|
||||||
// !:
|
|
||||||
// !: This will later be improved as we move to a CSS variable approach and rotate the lightness
|
|
||||||
|
|
||||||
export type RecipientColorMap = Record<number, RecipientColorStyles>;
|
export type TRecipientColor = 'readOnly' | (typeof AVAILABLE_RECIPIENT_COLORS)[number];
|
||||||
|
|
||||||
export type RecipientColorStyles = {
|
export type RecipientColorStyles = {
|
||||||
base: string;
|
base: string;
|
||||||
@@ -11,128 +9,89 @@ export type RecipientColorStyles = {
|
|||||||
baseRingHover: string;
|
baseRingHover: string;
|
||||||
baseTextHover: string;
|
baseTextHover: string;
|
||||||
fieldButton: string;
|
fieldButton: string;
|
||||||
|
fieldButtonText: string;
|
||||||
fieldItem: string;
|
fieldItem: string;
|
||||||
fieldItemInitials: string;
|
fieldItemInitials: string;
|
||||||
comboxBoxTrigger: string;
|
comboBoxTrigger: string;
|
||||||
comboxBoxItem: string;
|
comboBoxItem: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_RECT_BACKGROUND = 'rgba(255, 255, 255, 0.95)';
|
export const DEFAULT_RECT_BACKGROUND = 'rgba(255, 255, 255, 0.95)';
|
||||||
|
|
||||||
// !: values of the declared variable to do all the background, border and shadow styles.
|
// !: values of the declared variable to do all the background, border and shadow styles.
|
||||||
export const RECIPIENT_COLOR_STYLES = {
|
const RECIPIENT_COLOR_STYLES: Record<TRecipientColor, () => RecipientColorStyles> = {
|
||||||
readOnly: {
|
readOnly: (): RecipientColorStyles => ({
|
||||||
base: 'ring-neutral-400',
|
base: 'ring-neutral-400',
|
||||||
baseRing: 'rgba(176, 176, 176, 1)',
|
baseRing: 'rgba(176, 176, 176, 1)',
|
||||||
baseRingHover: 'rgba(176, 176, 176, 1)',
|
baseRingHover: 'rgba(176, 176, 176, 1)',
|
||||||
baseTextHover: 'rgba(176, 176, 176, 1)',
|
baseTextHover: 'rgba(176, 176, 176, 1)',
|
||||||
fieldButton: 'border-neutral-400 hover:border-neutral-400',
|
fieldButton: 'border-neutral-400 hover:border-neutral-400',
|
||||||
|
fieldButtonText: '',
|
||||||
fieldItem: 'group/field-item rounded-[2px]',
|
fieldItem: 'group/field-item rounded-[2px]',
|
||||||
fieldItemInitials: '',
|
fieldItemInitials: '',
|
||||||
comboxBoxTrigger:
|
comboBoxTrigger:
|
||||||
'ring-2 ring-recipient-green shadow-[0_0_0_5px_hsl(var(--recipient-green)/10%),0_0_0_2px_hsl(var(--recipient-green)/60%),0_0_0_0.5px_hsl(var(--recipient-green))]',
|
'ring-2 ring-recipient-green shadow-[0_0_0_5px_hsl(var(--recipient-green)/10%),0_0_0_2px_hsl(var(--recipient-green)/60%),0_0_0_0.5px_hsl(var(--recipient-green))]',
|
||||||
comboxBoxItem: '',
|
comboBoxItem: '',
|
||||||
},
|
}),
|
||||||
|
green: once(() => generateStyles('green')),
|
||||||
green: {
|
blue: once(() => generateStyles('blue')),
|
||||||
base: 'ring-recipient-green hover:bg-recipient-green/30',
|
purple: once(() => generateStyles('purple')),
|
||||||
baseRing: 'rgba(122, 195, 85, 1)',
|
orange: once(() => generateStyles('orange')),
|
||||||
baseRingHover: 'rgba(122, 195, 85, 0.3)',
|
yellow: once(() => generateStyles('yellow')),
|
||||||
baseTextHover: 'rgba(122, 195, 85, 1)',
|
pink: once(() => generateStyles('pink')),
|
||||||
fieldButton: 'hover:border-recipient-green hover:bg-recipient-green/30 ',
|
|
||||||
fieldItem: 'group/field-item rounded-[2px]',
|
|
||||||
fieldItemInitials: 'group-hover/field-item:bg-recipient-green',
|
|
||||||
comboxBoxTrigger:
|
|
||||||
'ring-2 ring-recipient-green hover:bg-recipient-green/15 active:bg-recipient-green/15 shadow-[0_0_0_5px_hsl(var(--recipient-green)/10%),0_0_0_2px_hsl(var(--recipient-green)/60%),0_0_0_0.5px_hsl(var(--recipient-green))]',
|
|
||||||
comboxBoxItem: 'hover:bg-recipient-green/15 active:bg-recipient-green/15',
|
|
||||||
},
|
|
||||||
|
|
||||||
blue: {
|
|
||||||
base: 'ring-recipient-blue hover:bg-recipient-blue/30',
|
|
||||||
baseRing: 'rgba(56, 123, 199, 1)',
|
|
||||||
baseRingHover: 'rgba(56, 123, 199, 0.3)',
|
|
||||||
baseTextHover: 'rgba(56, 123, 199, 1)',
|
|
||||||
fieldButton: 'hover:border-recipient-blue hover:bg-recipient-blue/30',
|
|
||||||
fieldItem: 'group/field-item rounded-[2px]',
|
|
||||||
fieldItemInitials: 'group-hover/field-item:bg-recipient-blue',
|
|
||||||
comboxBoxTrigger:
|
|
||||||
'ring-2 ring-recipient-blue hover:bg-recipient-blue/15 active:bg-recipient-blue/15 shadow-[0_0_0_5px_hsl(var(--recipient-blue)/10%),0_0_0_2px_hsl(var(--recipient-blue)/60%),0_0_0_0.5px_hsl(var(--recipient-blue))]',
|
|
||||||
comboxBoxItem: 'ring-recipient-blue hover:bg-recipient-blue/15 active:bg-recipient-blue/15',
|
|
||||||
},
|
|
||||||
|
|
||||||
purple: {
|
|
||||||
base: 'ring-recipient-purple hover:bg-recipient-purple/30',
|
|
||||||
baseRing: 'rgba(151, 71, 255, 1)',
|
|
||||||
baseRingHover: 'rgba(151, 71, 255, 0.3)',
|
|
||||||
baseTextHover: 'rgba(151, 71, 255, 1)',
|
|
||||||
fieldButton: 'hover:border-recipient-purple hover:bg-recipient-purple/30',
|
|
||||||
fieldItem: 'group/field-item rounded-[2px]',
|
|
||||||
fieldItemInitials: 'group-hover/field-item:bg-recipient-purple',
|
|
||||||
comboxBoxTrigger:
|
|
||||||
'ring-2 ring-recipient-purple hover:bg-recipient-purple/15 active:bg-recipient-purple/15 shadow-[0_0_0_5px_hsl(var(--recipient-purple)/10%),0_0_0_2px_hsl(var(--recipient-purple)/60%),0_0_0_0.5px_hsl(var(--recipient-purple))]',
|
|
||||||
comboxBoxItem: 'hover:bg-recipient-purple/15 active:bg-recipient-purple/15',
|
|
||||||
},
|
|
||||||
|
|
||||||
orange: {
|
|
||||||
base: 'ring-recipient-orange hover:bg-recipient-orange/30',
|
|
||||||
baseRing: 'rgba(246, 159, 30, 1)',
|
|
||||||
baseRingHover: 'rgba(246, 159, 30, 0.3)',
|
|
||||||
baseTextHover: 'rgba(246, 159, 30, 1)',
|
|
||||||
fieldButton: 'hover:border-recipient-orange hover:bg-recipient-orange/30',
|
|
||||||
fieldItem: 'group/field-item rounded-[2px]',
|
|
||||||
fieldItemInitials: 'group-hover/field-item:bg-recipient-orange',
|
|
||||||
comboxBoxTrigger:
|
|
||||||
'ring-2 ring-recipient-orange hover:bg-recipient-orange/15 active:bg-recipient-orange/15 shadow-[0_0_0_5px_hsl(var(--recipient-orange)/10%),0_0_0_2px_hsl(var(--recipient-orange)/60%),0_0_0_0.5px_hsl(var(--recipient-orange))]',
|
|
||||||
comboxBoxItem: 'hover:bg-recipient-orange/15 active:bg-recipient-orange/15',
|
|
||||||
},
|
|
||||||
|
|
||||||
yellow: {
|
|
||||||
base: 'ring-recipient-yellow hover:bg-recipient-yellow/30',
|
|
||||||
baseRing: 'rgba(219, 186, 0, 1)',
|
|
||||||
baseRingHover: 'rgba(219, 186, 0, 0.3)',
|
|
||||||
baseTextHover: 'rgba(219, 186, 0, 1)',
|
|
||||||
fieldButton: 'hover:border-recipient-yellow hover:bg-recipient-yellow/30',
|
|
||||||
fieldItem: 'group/field-item rounded-[2px]',
|
|
||||||
fieldItemInitials: 'group-hover/field-item:bg-recipient-yellow',
|
|
||||||
comboxBoxTrigger:
|
|
||||||
'ring-2 ring-recipient-yellow hover:bg-recipient-yellow/15 active:bg-recipient-yellow/15 shadow-[0_0_0_5px_hsl(var(--recipient-yellow)/10%),0_0_0_2px_hsl(var(--recipient-yellow)/60%),0_0_0_0.5px_hsl(var(--recipient-yellow))]',
|
|
||||||
comboxBoxItem: 'hover:bg-recipient-yellow/15 active:bg-recipient-yellow/15',
|
|
||||||
},
|
|
||||||
|
|
||||||
pink: {
|
|
||||||
base: 'ring-recipient-pink hover:bg-recipient-pink/30',
|
|
||||||
baseRing: 'rgba(217, 74, 186, 1)',
|
|
||||||
baseRingHover: 'rgba(217, 74, 186, 0.3)',
|
|
||||||
baseTextHover: 'rgba(217, 74, 186, 1)',
|
|
||||||
fieldButton: 'hover:border-recipient-pink hover:bg-recipient-pink/30',
|
|
||||||
fieldItem: 'group/field-item rounded-[2px]',
|
|
||||||
fieldItemInitials: 'group-hover/field-item:bg-recipient-pink',
|
|
||||||
comboxBoxTrigger:
|
|
||||||
'ring-2 ring-recipient-pink hover:bg-recipient-pink/15 active:bg-recipient-pink/15 shadow-[0_0_0_5px_hsl(var(--recipient-pink)/10%),0_0_0_2px_hsl(var(--recipient-pink)/60%),0_0_0_0.5px_hsl(var(--recipient-pink',
|
|
||||||
comboxBoxItem: 'hover:bg-recipient-pink/15 active:bg-recipient-pink/15',
|
|
||||||
},
|
|
||||||
} satisfies Record<string, RecipientColorStyles>;
|
|
||||||
|
|
||||||
export type TRecipientColor = keyof typeof RECIPIENT_COLOR_STYLES;
|
|
||||||
|
|
||||||
export const AVAILABLE_RECIPIENT_COLORS = [
|
|
||||||
'green',
|
|
||||||
'blue',
|
|
||||||
'purple',
|
|
||||||
'orange',
|
|
||||||
'yellow',
|
|
||||||
'pink',
|
|
||||||
] satisfies TRecipientColor[];
|
|
||||||
|
|
||||||
export const useRecipientColors = (index: number) => {
|
|
||||||
const key = AVAILABLE_RECIPIENT_COLORS[index % AVAILABLE_RECIPIENT_COLORS.length];
|
|
||||||
|
|
||||||
return RECIPIENT_COLOR_STYLES[key];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getRecipientColorStyles = (index: number) => {
|
const generateStyles = (recipientColor: TRecipientColor): RecipientColorStyles => {
|
||||||
// Disabling the rule since the hook doesn't do anything special and can
|
const { bg, border, ring, text } = CSS_PROPERTY;
|
||||||
// be used universally.
|
const { active, hover, groupHover, groupHoverFieldItem } = CSS_VARIANT;
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
||||||
return useRecipientColors(index);
|
const name = `recipient-${recipientColor}`;
|
||||||
|
const value = getComputedStyle(document.documentElement).getPropertyValue(`--${name}`);
|
||||||
|
const color = colord(`hsl(${value})`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
base: `${ring}-${name} ${hover}:${bg}-${name}/30`,
|
||||||
|
baseRing: color.toRgbString(),
|
||||||
|
baseRingHover: color.alpha(0.3).toRgbString(),
|
||||||
|
baseTextHover: color.toRgbString(),
|
||||||
|
fieldButton: `${hover}:${border}-${name} ${hover}:${bg}-${name}/30`,
|
||||||
|
fieldButtonText: `${groupHover}:${text}-${name}`,
|
||||||
|
fieldItem: 'group/field-item rounded-[2px]',
|
||||||
|
fieldItemInitials: `${groupHoverFieldItem}:${bg}-${name}`,
|
||||||
|
comboBoxTrigger: `ring-2 ${ring}-${name} ${hover}:${bg}-${name}/15 ${active}:${bg}-${name}/15 shadow-[0_0_0_5px_hsl(var(--${name})/10%),0_0_0_2px_hsl(var(--${name})/60%),0_0_0_0.5px_hsl(var(--${name}))]`,
|
||||||
|
comboBoxItem: `${hover}:${bg}-${name}/15 ${active}:${bg}-${name}/15`,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const CSS_PROPERTY = {
|
||||||
|
bg: 'bg',
|
||||||
|
border: 'border',
|
||||||
|
ring: 'ring',
|
||||||
|
text: 'text',
|
||||||
|
};
|
||||||
|
|
||||||
|
const CSS_VARIANT = {
|
||||||
|
active: 'active',
|
||||||
|
groupHover: 'group-hover',
|
||||||
|
groupHoverFieldItem: 'group-hover/field-item',
|
||||||
|
hover: 'hover',
|
||||||
|
};
|
||||||
|
|
||||||
|
const AVAILABLE_RECIPIENT_COLORS = ['green', 'blue', 'purple', 'orange', 'yellow', 'pink'] as const;
|
||||||
|
|
||||||
|
export const RECIPIENT_DYNAMIC_CLASS = {
|
||||||
|
pattern: new RegExp(
|
||||||
|
`(${Object.values(CSS_PROPERTY).join('|')})-recipient-(${AVAILABLE_RECIPIENT_COLORS.join('|')})(\\/(15|30))?$`,
|
||||||
|
),
|
||||||
|
variants: Object.values(CSS_VARIANT),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getRecipientColor = (index: number) => {
|
||||||
|
return AVAILABLE_RECIPIENT_COLORS[Math.max(index, 0) % AVAILABLE_RECIPIENT_COLORS.length];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getRecipientColorStyles = (colorOrIndex: TRecipientColor | number) => {
|
||||||
|
const color = typeof colorOrIndex === 'number' ? getRecipientColor(colorOrIndex) : colorOrIndex;
|
||||||
|
|
||||||
|
return RECIPIENT_COLOR_STYLES[color]();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import {
|
|||||||
} from '@documenso/lib/utils/recipients';
|
} from '@documenso/lib/utils/recipients';
|
||||||
|
|
||||||
import { FieldToolTip } from '../../components/field/field-tooltip';
|
import { FieldToolTip } from '../../components/field/field-tooltip';
|
||||||
import { useRecipientColors } from '../../lib/recipient-colors';
|
import { getRecipientColorStyles } from '../../lib/recipient-colors';
|
||||||
import { cn } from '../../lib/utils';
|
import { cn } from '../../lib/utils';
|
||||||
import { Alert, AlertDescription } from '../alert';
|
import { Alert, AlertDescription } from '../alert';
|
||||||
import { Card, CardContent } from '../card';
|
import { Card, CardContent } from '../card';
|
||||||
@@ -180,9 +180,7 @@ export const AddFieldsFormPartial = ({
|
|||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
const selectedSignerIndex = recipients.findIndex((r) => r.id === selectedSigner?.id);
|
const selectedSignerIndex = recipients.findIndex((r) => r.id === selectedSigner?.id);
|
||||||
const selectedSignerStyles = useRecipientColors(
|
const selectedSignerStyles = getRecipientColorStyles(selectedSignerIndex);
|
||||||
selectedSignerIndex === -1 ? 0 : selectedSignerIndex,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [validateUninsertedFields, setValidateUninsertedFields] = useState(false);
|
const [validateUninsertedFields, setValidateUninsertedFields] = useState(false);
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
|
|||||||
import type { TFieldMetaSchema } from '@documenso/lib/types/field-meta';
|
import type { TFieldMetaSchema } from '@documenso/lib/types/field-meta';
|
||||||
import { ZCheckboxFieldMeta, ZRadioFieldMeta } from '@documenso/lib/types/field-meta';
|
import { ZCheckboxFieldMeta, ZRadioFieldMeta } from '@documenso/lib/types/field-meta';
|
||||||
|
|
||||||
import { useRecipientColors } from '../../lib/recipient-colors';
|
import { getRecipientColorStyles } from '../../lib/recipient-colors';
|
||||||
import { cn } from '../../lib/utils';
|
import { cn } from '../../lib/utils';
|
||||||
import { FieldContent } from './field-content';
|
import { FieldContent } from './field-content';
|
||||||
import type { TDocumentFlowFormSchema } from './types';
|
import type { TDocumentFlowFormSchema } from './types';
|
||||||
@@ -100,7 +100,7 @@ const FieldItemInner = ({
|
|||||||
`${PDF_VIEWER_PAGE_SELECTOR}[data-page-number="${field.pageNumber}"]`,
|
`${PDF_VIEWER_PAGE_SELECTOR}[data-page-number="${field.pageNumber}"]`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const signerStyles = useRecipientColors(recipientIndex);
|
const signerStyles = getRecipientColorStyles(recipientIndex);
|
||||||
|
|
||||||
const isDevMode = searchParams.get('devmode') === 'true';
|
const isDevMode = searchParams.get('devmode') === 'true';
|
||||||
|
|
||||||
|
|||||||
@@ -102,12 +102,8 @@ export const RecipientSelector = ({
|
|||||||
role="combobox"
|
role="combobox"
|
||||||
className={cn(
|
className={cn(
|
||||||
'bg-background text-muted-foreground hover:text-foreground justify-between font-normal',
|
'bg-background text-muted-foreground hover:text-foreground justify-between font-normal',
|
||||||
getRecipientColorStyles(
|
getRecipientColorStyles(recipients.findIndex((r) => r.id === selectedRecipient?.id))
|
||||||
Math.max(
|
.comboBoxTrigger,
|
||||||
recipients.findIndex((r) => r.id === selectedRecipient?.id),
|
|
||||||
0,
|
|
||||||
),
|
|
||||||
).comboxBoxTrigger,
|
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -151,12 +147,8 @@ export const RecipientSelector = ({
|
|||||||
key={recipient.id}
|
key={recipient.id}
|
||||||
className={cn(
|
className={cn(
|
||||||
'px-2 last:mb-1 [&:not(:first-child)]:mt-1',
|
'px-2 last:mb-1 [&:not(:first-child)]:mt-1',
|
||||||
getRecipientColorStyles(
|
getRecipientColorStyles(recipients.findIndex((r) => r.id === recipient.id))
|
||||||
Math.max(
|
.comboBoxItem,
|
||||||
recipients.findIndex((r) => r.id === recipient.id),
|
|
||||||
0,
|
|
||||||
),
|
|
||||||
).comboxBoxItem,
|
|
||||||
{
|
{
|
||||||
'text-muted-foreground': recipient.sendStatus === SendStatus.SENT,
|
'text-muted-foreground': recipient.sendStatus === SendStatus.SENT,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ import { FRIENDLY_FIELD_TYPE } from '@documenso/ui/primitives/document-flow/type
|
|||||||
import { Popover, PopoverContent, PopoverTrigger } from '@documenso/ui/primitives/popover';
|
import { Popover, PopoverContent, PopoverTrigger } from '@documenso/ui/primitives/popover';
|
||||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||||
|
|
||||||
import { getRecipientColorStyles, useRecipientColors } from '../../lib/recipient-colors';
|
import { getRecipientColorStyles } from '../../lib/recipient-colors';
|
||||||
import type { FieldFormType } from '../document-flow/add-fields';
|
import type { FieldFormType } from '../document-flow/add-fields';
|
||||||
import { FieldAdvancedSettings } from '../document-flow/field-item-advanced-settings';
|
import { FieldAdvancedSettings } from '../document-flow/field-item-advanced-settings';
|
||||||
import { Form } from '../form/form';
|
import { Form } from '../form/form';
|
||||||
@@ -158,9 +158,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||||||
const [showRecipientsSelector, setShowRecipientsSelector] = useState(false);
|
const [showRecipientsSelector, setShowRecipientsSelector] = useState(false);
|
||||||
|
|
||||||
const selectedSignerIndex = recipients.findIndex((r) => r.id === selectedSigner?.id);
|
const selectedSignerIndex = recipients.findIndex((r) => r.id === selectedSigner?.id);
|
||||||
const selectedSignerStyles = useRecipientColors(
|
const selectedSignerStyles = getRecipientColorStyles(selectedSignerIndex);
|
||||||
selectedSignerIndex === -1 ? 0 : selectedSignerIndex,
|
|
||||||
);
|
|
||||||
|
|
||||||
const onFieldCopy = useCallback(
|
const onFieldCopy = useCallback(
|
||||||
(event?: KeyboardEvent | null, options?: { duplicate?: boolean; duplicateAll?: boolean }) => {
|
(event?: KeyboardEvent | null, options?: { duplicate?: boolean; duplicateAll?: boolean }) => {
|
||||||
@@ -653,7 +651,7 @@ export const AddTemplateFieldsFormPartial = ({
|
|||||||
role="combobox"
|
role="combobox"
|
||||||
className={cn(
|
className={cn(
|
||||||
'mb-12 mt-2 justify-between bg-background font-normal text-muted-foreground hover:text-foreground',
|
'mb-12 mt-2 justify-between bg-background font-normal text-muted-foreground hover:text-foreground',
|
||||||
selectedSignerStyles?.comboxBoxTrigger,
|
selectedSignerStyles?.comboBoxTrigger,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{selectedSigner?.email &&
|
{selectedSigner?.email &&
|
||||||
@@ -710,11 +708,8 @@ export const AddTemplateFieldsFormPartial = ({
|
|||||||
className={cn(
|
className={cn(
|
||||||
'px-2 last:mb-1 [&:not(:first-child)]:mt-1',
|
'px-2 last:mb-1 [&:not(:first-child)]:mt-1',
|
||||||
getRecipientColorStyles(
|
getRecipientColorStyles(
|
||||||
Math.max(
|
recipients.findIndex((r) => r.id === recipient.id),
|
||||||
recipients.findIndex((r) => r.id === recipient.id),
|
)?.comboBoxItem,
|
||||||
0,
|
|
||||||
),
|
|
||||||
)?.comboxBoxItem,
|
|
||||||
)}
|
)}
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setSelectedSigner(recipient);
|
setSelectedSigner(recipient);
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
const baseConfig = require('@documenso/tailwind-config');
|
const baseConfig = require('@documenso/tailwind-config');
|
||||||
|
const { RECIPIENT_DYNAMIC_CLASS } = require('./lib/recipient-colors');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
...baseConfig,
|
presets: [baseConfig],
|
||||||
content: [
|
content: [
|
||||||
...baseConfig.content,
|
...baseConfig.content,
|
||||||
'./primitives/**/*.{ts,tsx}',
|
'./primitives/**/*.{ts,tsx}',
|
||||||
'./components/**/*.{ts,tsx}',
|
'./components/**/*.{ts,tsx}',
|
||||||
'./lib/**/*.{ts,tsx}',
|
'./lib/**/*.{ts,tsx}',
|
||||||
],
|
],
|
||||||
|
safelist: [RECIPIENT_DYNAMIC_CLASS],
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user