mirror of
https://github.com/documenso/documenso.git
synced 2026-09-30 16:54:34 +10:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4105e47eb | ||
|
|
b8b98f70c0 | ||
|
|
22c697f712 |
@@ -49,7 +49,7 @@ Use the `cssVars` prop on any embed component to override default colors, spacin
|
||||
| `widgetForeground` | Widget text color |
|
||||
| `border` | Default border color |
|
||||
| `input` | Input field border color |
|
||||
| `primary` | Primary action/button color. The loading spinner on fields also uses this color. |
|
||||
| `primary` | Primary action/button color |
|
||||
| `primaryForeground` | Primary action/button text color |
|
||||
| `secondary` | Secondary action/button color |
|
||||
| `secondaryForeground` | Secondary button text color |
|
||||
|
||||
@@ -12,11 +12,20 @@ import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@documenso/ui/primitives/accordion';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import { ColorPicker } from '@documenso/ui/primitives/color-picker';
|
||||
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel } from '@documenso/ui/primitives/form/form';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@documenso/ui/primitives/select';
|
||||
import { Textarea } from '@documenso/ui/primitives/textarea';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import type { TeamGlobalSettings } from '@prisma/client';
|
||||
import { Loader } from 'lucide-react';
|
||||
@@ -37,14 +46,17 @@ const ZBrandingPreferencesFormSchema = z.object({
|
||||
.instanceof(File)
|
||||
.refine(
|
||||
(file) => file.size <= BRANDING_LOGO_MAX_SIZE_BYTES,
|
||||
`File size must be less than ${BRANDING_LOGO_MAX_SIZE_MB}MB`,
|
||||
msg`File size must be less than ${BRANDING_LOGO_MAX_SIZE_MB}MB`,
|
||||
)
|
||||
.refine(
|
||||
(file) => BRANDING_LOGO_ALLOWED_TYPES.includes(file.type),
|
||||
msg`Only .jpg, .png, and .webp files are accepted`,
|
||||
)
|
||||
.refine((file) => BRANDING_LOGO_ALLOWED_TYPES.includes(file.type), 'Only .jpg, .png, and .webp files are accepted')
|
||||
.nullish(),
|
||||
brandingUrl: z.string().url().optional().or(z.literal('')),
|
||||
brandingCompanyDetails: z.string().max(500).optional(),
|
||||
brandingUrl: z.string().url(msg`Please enter a valid URL`).optional().or(z.literal('')),
|
||||
brandingCompanyDetails: z.string().max(500, msg`Brand details must be less than 500 characters`).optional(),
|
||||
brandingColors: ZCssVarsSchema.default({}),
|
||||
brandingCss: z.string().max(10_000).default(''),
|
||||
brandingCss: z.string().max(10_000, msg`Custom CSS must be less than 10,000 characters`).default(''),
|
||||
});
|
||||
|
||||
export type TBrandingPreferencesFormSchema = z.infer<typeof ZBrandingPreferencesFormSchema>;
|
||||
@@ -349,6 +361,8 @@ export function BrandingPreferencesForm({
|
||||
</span>
|
||||
)}
|
||||
</FormDescription>
|
||||
|
||||
<FormMessage />
|
||||
</div>
|
||||
</InheritableField>
|
||||
)}
|
||||
@@ -379,6 +393,8 @@ export function BrandingPreferencesForm({
|
||||
</span>
|
||||
)}
|
||||
</FormDescription>
|
||||
|
||||
<FormMessage />
|
||||
</InheritableField>
|
||||
)}
|
||||
/>
|
||||
@@ -413,6 +429,8 @@ export function BrandingPreferencesForm({
|
||||
</span>
|
||||
)}
|
||||
</FormDescription>
|
||||
|
||||
<FormMessage />
|
||||
</InheritableField>
|
||||
)}
|
||||
/>
|
||||
@@ -597,6 +615,8 @@ export function BrandingPreferencesForm({
|
||||
<FormDescription>
|
||||
<Trans>Border radius size in REM units (e.g. 0.5rem).</Trans>
|
||||
</FormDescription>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
@@ -634,6 +654,8 @@ export function BrandingPreferencesForm({
|
||||
shown after you save.
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -51,6 +51,12 @@ export async function rejectDocumentWithToken({ token, id, reason, requestMetada
|
||||
});
|
||||
}
|
||||
|
||||
if (recipient.signingStatus !== SigningStatus.NOT_SIGNED) {
|
||||
throw new AppError(AppErrorCode.INVALID_REQUEST, {
|
||||
message: `Recipient ${recipient.id} has already actioned this document`,
|
||||
});
|
||||
}
|
||||
|
||||
assertRecipientNotExpired(recipient);
|
||||
|
||||
// Update the recipient status to rejected
|
||||
|
||||
@@ -166,19 +166,3 @@ export const resolveFieldCanvasStyle = (
|
||||
|
||||
return style;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve the `--primary` color from the same cascade as the fields, so canvas
|
||||
* elements such as the loading spinner follow team and embed branding.
|
||||
*/
|
||||
export const resolvePrimaryColor = () => {
|
||||
const $anchor = document.querySelector(FIELD_PROBE_ANCHOR_SELECTOR);
|
||||
|
||||
if (!$anchor) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const color = colord(`hsl(${window.getComputedStyle($anchor).getPropertyValue('--primary')})`);
|
||||
|
||||
return color.isValid() ? color.toRgbString() : undefined;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { DEFAULT_RECT_BACKGROUND, getRecipientColorStyles } from '@documenso/ui/lib/recipient-colors';
|
||||
import Konva from 'konva';
|
||||
|
||||
import { resolvePrimaryColor } from './field-canvas-style';
|
||||
import type { FieldToRender, RenderFieldElementOptions } from './field-renderer';
|
||||
import { calculateFieldPosition } from './field-renderer';
|
||||
|
||||
@@ -95,7 +94,7 @@ export const createSpinner = ({ fieldWidth, fieldHeight }: { fieldWidth: number;
|
||||
outerRadius: spinnerSize / 2,
|
||||
angle: 270,
|
||||
rotation: 0,
|
||||
fill: resolvePrimaryColor() ?? 'rgba(122, 195, 85, 1)',
|
||||
fill: 'rgba(122, 195, 85, 1)',
|
||||
lineCap: 'round',
|
||||
});
|
||||
|
||||
|
||||
@@ -41,6 +41,15 @@ export const SignaturePadDialog = ({
|
||||
const [showSignatureModal, setShowSignatureModal] = useState(false);
|
||||
const [signature, setSignature] = useState<string>(value ?? '');
|
||||
|
||||
const onOpenChange = (open: boolean) => {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSignature(value ?? '');
|
||||
setShowSignatureModal(open);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
@@ -62,7 +71,7 @@ export const SignaturePadDialog = ({
|
||||
type="button"
|
||||
disabled={disabled}
|
||||
className="absolute inset-0 flex items-center justify-center bg-transparent"
|
||||
onClick={() => setShowSignatureModal(true)}
|
||||
onClick={() => onOpenChange(true)}
|
||||
whileHover="onHover"
|
||||
>
|
||||
{!value && !disableAnimation && (
|
||||
@@ -109,7 +118,7 @@ export const SignaturePadDialog = ({
|
||||
)}
|
||||
</motion.button>
|
||||
|
||||
<Dialog open={showSignatureModal} onOpenChange={disabled ? undefined : setShowSignatureModal}>
|
||||
<Dialog open={showSignatureModal} onOpenChange={onOpenChange}>
|
||||
<DialogContent hideClose={true} className="p-6 pt-4">
|
||||
<SignaturePad
|
||||
id="signature"
|
||||
@@ -135,7 +144,7 @@ export const SignaturePadDialog = ({
|
||||
disabled={!signature}
|
||||
onClick={() => {
|
||||
onChange(signature);
|
||||
setShowSignatureModal(false);
|
||||
onOpenChange(false);
|
||||
}}
|
||||
>
|
||||
{dialogConfirmText ? parseMessageDescriptor(i18n._, dialogConfirmText) : <Trans>Next</Trans>}
|
||||
|
||||
Reference in New Issue
Block a user