feat: add custom branding for signing pages (#2785)

Platform-plan organisations and teams can now customise non-embed
signing pages with six brand colour tokens, a border-radius, and
a free-text custom CSS block (up to 256 KB).

- Stored on OrganisationGlobalSettings / TeamGlobalSettings;
  teams inherit from the org via brandingEnabled === null.
- CSS is sanitised on save (PostCSS) so we can inline it at SSR
  with no per-render parsing.
- Rendered via a nonce'd <style> scoped under .documenso-branded,
  using native CSS nesting so user selectors don't need scoping.
- Gated on the existing embedSigningWhiteLabel claim (or
  self-hosted) — reuses the embed white-label decision.
This commit is contained in:
Lucas Smith
2026-05-11 13:03:02 +10:00
committed by GitHub
parent a197bf113f
commit 0b86ece1d5
37 changed files with 2055 additions and 301 deletions
+12 -2
View File
@@ -1,7 +1,7 @@
import type { HTMLAttributes } from 'react';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { HexColorInput, HexColorPicker } from 'react-colorful';
import { HexColorInput, HexColorPicker, setNonce } from 'react-colorful';
import { cn } from '../lib/utils';
import { Popover, PopoverContent, PopoverTrigger } from './popover';
@@ -11,6 +11,7 @@ export type ColorPickerProps = {
value: string;
defaultValue?: string;
onChange: (color: string) => void;
nonce?: string;
} & HTMLAttributes<HTMLDivElement>;
export const ColorPicker = ({
@@ -19,6 +20,7 @@ export const ColorPicker = ({
value,
defaultValue = '#000000',
onChange,
nonce,
...props
}: ColorPickerProps) => {
const [color, setColor] = useState(value || defaultValue);
@@ -39,6 +41,12 @@ export const ColorPicker = ({
onChange(inputColor);
};
useEffect(() => {
if (nonce) {
setNonce(nonce);
}
}, [nonce]);
return (
<Popover>
<PopoverTrigger>
@@ -57,6 +65,7 @@ export const ColorPicker = ({
color={color}
onChange={onColorChange}
aria-disabled={disabled}
nonce={nonce}
{...props}
/>
@@ -72,6 +81,7 @@ export const ColorPicker = ({
}
}}
disabled={disabled}
nonce={nonce}
/>
</PopoverContent>
</Popover>