mirror of
https://github.com/documenso/documenso
synced 2026-04-21 13:27:18 +00:00
feat: support language in embedding (#2364)
This commit is contained in:
parent
f48aa84c9e
commit
5dcdac7ecd
17 changed files with 142 additions and 22 deletions
|
|
@ -141,6 +141,7 @@ const TemplateEditor = ({ presignToken, templateId }) => {
|
|||
| `css` | `string` | No | Custom CSS string (Platform Plan) |
|
||||
| `cssVars` | `object` | No | [CSS variable](/docs/developers/embedding/css-variables) overrides (Platform Plan) |
|
||||
| `darkModeDisabled` | `boolean` | No | Disable dark mode (Platform Plan) |
|
||||
| `language` | `string` | No | Set the UI language. See [Supported Languages](https://github.com/documenso/documenso/tree/main/packages/lib/constants/locales.ts) |
|
||||
| `className` | `string` | No | CSS class for the iframe |
|
||||
| `features` | `object` | No | Feature toggles for the authoring experience |
|
||||
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ const EnvelopeEditor = ({ presignToken, envelopeId }) => {
|
|||
| `css` | `string` | No | Custom CSS string (Platform Plan) |
|
||||
| `cssVars` | `object` | No | [CSS variable](/docs/developers/embedding/css-variables) overrides (Platform Plan) |
|
||||
| `darkModeDisabled` | `boolean` | No | Disable dark mode (Platform Plan) |
|
||||
| `language` | `string` | No | Set the UI language. See [Supported Languages](https://github.com/documenso/documenso/tree/main/packages/lib/constants/locales.ts) |
|
||||
| `className` | `string` | No | CSS class for the iframe |
|
||||
| `features` | `object` | No | Feature toggles for the authoring experience |
|
||||
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ If you prefer not to use any SDK, you can embed signing using [Direct Links](/do
|
|||
| `css` | `string` | Custom CSS string (Platform Plan). |
|
||||
| `cssVars` | `object` | CSS variable overrides for theming (Platform Plan). |
|
||||
| `darkModeDisabled` | `boolean` | Disable dark mode in the embed (Platform Plan). |
|
||||
| `language` | `string` | Set the UI language. See [Supported Languages](https://github.com/documenso/documenso/tree/main/packages/lib/constants/locales.ts). |
|
||||
| `onDocumentReady` | `function` | Called when the document is loaded and ready. |
|
||||
| `onDocumentCompleted` | `function` | Called when signing is completed. |
|
||||
| `onDocumentError` | `function` | Called when an error occurs. |
|
||||
|
|
@ -175,6 +176,7 @@ If you prefer not to use any SDK, you can embed signing using [Direct Links](/do
|
|||
| `host` | `string` | Documenso instance URL. Defaults to `https://app.documenso.com`. |
|
||||
| `name` | `string` | Pre-fill the signer's name. |
|
||||
| `lockName` | `boolean` | Prevent the signer from changing their name. |
|
||||
| `language` | `string` | Set the UI language. See [Supported Languages](https://github.com/documenso/documenso/tree/main/packages/lib/constants/locales.ts). |
|
||||
| `onDocumentReady` | `function` | Called when the document is loaded and ready. |
|
||||
| `onDocumentCompleted` | `function` | Called when signing is completed. |
|
||||
| `onDocumentError` | `function` | Called when an error occurs. |
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { useSearchParams } from 'react-router';
|
|||
|
||||
import { useThrottleFn } from '@documenso/lib/client-only/hooks/use-throttle-fn';
|
||||
import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
|
||||
import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n';
|
||||
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
|
||||
import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones';
|
||||
import { ZDirectTemplateEmbedDataSchema } from '@documenso/lib/types/embed-direct-template-schema';
|
||||
|
|
@ -26,6 +27,7 @@ import {
|
|||
} from '@documenso/lib/utils/advanced-fields-helpers';
|
||||
import { getDocumentDataUrlForPdfViewer } from '@documenso/lib/utils/envelope-download';
|
||||
import { sortFieldsByPosition, validateFieldsInserted } from '@documenso/lib/utils/fields';
|
||||
import { dynamicActivate } from '@documenso/lib/utils/i18n';
|
||||
import { isSignatureFieldType } from '@documenso/prisma/guards/is-signature-field';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import type {
|
||||
|
|
@ -290,12 +292,19 @@ export const EmbedDirectTemplateClientPage = ({
|
|||
cssVars: data.cssVars,
|
||||
});
|
||||
}
|
||||
|
||||
if (data.language && data.language !== APP_I18N_OPTIONS.sourceLang) {
|
||||
void dynamicActivate(data.language).finally(() => {
|
||||
setHasFinishedInit(true);
|
||||
});
|
||||
} else {
|
||||
setHasFinishedInit(true);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setHasFinishedInit(true);
|
||||
}
|
||||
|
||||
setHasFinishedInit(true);
|
||||
|
||||
// !: While the two setters are stable we still want to ensure we're avoiding
|
||||
// !: re-renders.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
|
|
|||
|
|
@ -8,11 +8,13 @@ import { type Field, RecipientRole, SigningStatus } from '@prisma/client';
|
|||
import { LucideChevronDown, LucideChevronUp } from 'lucide-react';
|
||||
|
||||
import { useThrottleFn } from '@documenso/lib/client-only/hooks/use-throttle-fn';
|
||||
import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n';
|
||||
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
|
||||
import { ZSignDocumentEmbedDataSchema } from '@documenso/lib/types/embed-document-sign-schema';
|
||||
import { isFieldUnsignedAndRequired } from '@documenso/lib/utils/advanced-fields-helpers';
|
||||
import { getDocumentDataUrlForPdfViewer } from '@documenso/lib/utils/envelope-download';
|
||||
import { sortFieldsByPosition, validateFieldsInserted } from '@documenso/lib/utils/fields';
|
||||
import { dynamicActivate } from '@documenso/lib/utils/i18n';
|
||||
import { isSignatureFieldType } from '@documenso/prisma/guards/is-signature-field';
|
||||
import type { RecipientWithFields } from '@documenso/prisma/types/recipient-with-fields';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
|
|
@ -232,12 +234,19 @@ export const EmbedSignDocumentV1ClientPage = ({
|
|||
cssVars: data.cssVars,
|
||||
});
|
||||
}
|
||||
|
||||
if (data.language && data.language !== APP_I18N_OPTIONS.sourceLang) {
|
||||
void dynamicActivate(data.language).finally(() => {
|
||||
setHasFinishedInit(true);
|
||||
});
|
||||
} else {
|
||||
setHasFinishedInit(true);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setHasFinishedInit(true);
|
||||
}
|
||||
|
||||
setHasFinishedInit(true);
|
||||
|
||||
// !: While the two setters are stable we still want to ensure we're avoiding
|
||||
// !: re-renders.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ import { useEffect, useLayoutEffect, useState } from 'react';
|
|||
import { useLingui } from '@lingui/react';
|
||||
import { EnvelopeType } from '@prisma/client';
|
||||
|
||||
import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n';
|
||||
import { ZSignDocumentEmbedDataSchema } from '@documenso/lib/types/embed-document-sign-schema';
|
||||
import { mapSecondaryIdToDocumentId } from '@documenso/lib/utils/envelope';
|
||||
import { dynamicActivate } from '@documenso/lib/utils/i18n';
|
||||
|
||||
import { injectCss } from '~/utils/css-vars';
|
||||
|
||||
|
|
@ -162,12 +164,19 @@ export const EmbedSignDocumentV2ClientPage = ({
|
|||
cssVars: data.cssVars,
|
||||
});
|
||||
}
|
||||
|
||||
if (data.language && data.language !== APP_I18N_OPTIONS.sourceLang) {
|
||||
void dynamicActivate(data.language).finally(() => {
|
||||
setHasFinishedInit(true);
|
||||
});
|
||||
} else {
|
||||
setHasFinishedInit(true);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setHasFinishedInit(true);
|
||||
}
|
||||
|
||||
setHasFinishedInit(true);
|
||||
|
||||
// !: While the setters are stable we still want to ensure we're avoiding
|
||||
// !: re-renders.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ export default function EmbedPlaygroundPage() {
|
|||
() => (searchParams.get('envelopeType') as 'DOCUMENT' | 'TEMPLATE') || 'DOCUMENT',
|
||||
);
|
||||
const [folderId, setFolderId] = useState(() => searchParams.get('folderId') || '');
|
||||
const [language, setLanguage] = useState(() => searchParams.get('language') || '');
|
||||
|
||||
// Auto-launch if query params are present on mount
|
||||
const [iframeSrc, setIframeSrc] = useState<string | null>(null);
|
||||
|
|
@ -203,6 +204,7 @@ export default function EmbedPlaygroundPage() {
|
|||
envelopeId: string;
|
||||
envelopeType: string;
|
||||
folderId: string;
|
||||
language: string;
|
||||
}) => {
|
||||
const newParams = new URLSearchParams();
|
||||
|
||||
|
|
@ -230,6 +232,10 @@ export default function EmbedPlaygroundPage() {
|
|||
newParams.set('folderId', params.folderId);
|
||||
}
|
||||
|
||||
if (params.language) {
|
||||
newParams.set('language', params.language);
|
||||
}
|
||||
|
||||
const qs = newParams.toString();
|
||||
|
||||
void navigate(qs ? `?${qs}` : '.', { replace: true });
|
||||
|
|
@ -270,6 +276,7 @@ export default function EmbedPlaygroundPage() {
|
|||
externalId: externalId || undefined,
|
||||
type: mode === 'create' ? envelopeType : undefined,
|
||||
folderId: mode === 'create' && folderId ? folderId : undefined,
|
||||
language: language || undefined,
|
||||
darkModeDisabled: darkModeDisabled || undefined,
|
||||
css: rawCss || undefined,
|
||||
cssVars: Object.keys(filteredCssVars).length > 0 ? filteredCssVars : undefined,
|
||||
|
|
@ -299,7 +306,15 @@ export default function EmbedPlaygroundPage() {
|
|||
setIframeSrc(buildIframeSrc(basePath, presignToken, hash));
|
||||
setIframeKey((prev) => prev + 1);
|
||||
|
||||
updateQueryParams({ token: inputToken, externalId, mode, envelopeId, envelopeType, folderId });
|
||||
updateQueryParams({
|
||||
token: inputToken,
|
||||
externalId,
|
||||
mode,
|
||||
envelopeId,
|
||||
envelopeType,
|
||||
folderId,
|
||||
language,
|
||||
});
|
||||
};
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
|
|
@ -314,6 +329,7 @@ export default function EmbedPlaygroundPage() {
|
|||
envelopeId,
|
||||
envelopeType,
|
||||
folderId,
|
||||
language,
|
||||
generalFeatures,
|
||||
settingsFeatures,
|
||||
actionsFeatures,
|
||||
|
|
@ -333,6 +349,7 @@ export default function EmbedPlaygroundPage() {
|
|||
setEnvelopeId('');
|
||||
setEnvelopeType('DOCUMENT');
|
||||
setFolderId('');
|
||||
setLanguage('');
|
||||
setIframeSrc(null);
|
||||
setMessages([]);
|
||||
setTokenError(null);
|
||||
|
|
@ -477,6 +494,30 @@ export default function EmbedPlaygroundPage() {
|
|||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ marginBottom: '8px' }}>
|
||||
<label style={{ display: 'block', fontSize: '12px', fontWeight: 'bold' }}>
|
||||
Language (optional)
|
||||
</label>
|
||||
<select
|
||||
value={language}
|
||||
onChange={(e) => setLanguage(e.target.value)}
|
||||
style={{ width: '100%', padding: '4px', fontSize: '12px' }}
|
||||
>
|
||||
<option value="">Default (en)</option>
|
||||
<option value="de">German (de)</option>
|
||||
<option value="en">English (en)</option>
|
||||
<option value="es">Spanish (es)</option>
|
||||
<option value="fr">French (fr)</option>
|
||||
<option value="it">Italian (it)</option>
|
||||
<option value="ja">Japanese (ja)</option>
|
||||
<option value="ko">Korean (ko)</option>
|
||||
<option value="nl">Dutch (nl)</option>
|
||||
<option value="pl">Polish (pl)</option>
|
||||
<option value="pt-BR">Portuguese - Brazil (pt-BR)</option>
|
||||
<option value="zh">Chinese (zh)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<h3 style={{ fontSize: '14px', margin: '12px 0 4px' }}>Feature Flags</h3>
|
||||
|
||||
{renderCheckboxGroup('General', generalFeatures, setGeneralFeatures)}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
import { useLayoutEffect } from 'react';
|
||||
import { useLayoutEffect, useState } from 'react';
|
||||
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { Outlet, useLoaderData } from 'react-router';
|
||||
|
||||
import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n';
|
||||
import { verifyEmbeddingPresignToken } from '@documenso/lib/server-only/embedding-presign/verify-embedding-presign-token';
|
||||
import { getOrganisationClaimByTeamId } from '@documenso/lib/server-only/organisation/get-organisation-claims';
|
||||
import { ZBaseEmbedAuthoringSchema } from '@documenso/lib/types/embed-authoring-base-schema';
|
||||
import { dynamicActivate } from '@documenso/lib/utils/i18n';
|
||||
import { TrpcProvider } from '@documenso/trpc/react';
|
||||
import { Spinner } from '@documenso/ui/primitives/spinner';
|
||||
|
||||
import { injectCss } from '~/utils/css-vars';
|
||||
|
||||
|
|
@ -46,6 +49,8 @@ export const loader = async ({ request }: Route.LoaderArgs) => {
|
|||
export default function AuthoringLayout() {
|
||||
const { token, hasValidToken, allowEmbedAuthoringWhiteLabel } = useLoaderData<typeof loader>();
|
||||
|
||||
const [hasFinishedInit, setHasFinishedInit] = useState(false);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
try {
|
||||
const hash = window.location.hash.slice(1);
|
||||
|
|
@ -55,10 +60,11 @@ export default function AuthoringLayout() {
|
|||
);
|
||||
|
||||
if (!result.success) {
|
||||
setHasFinishedInit(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const { css, cssVars, darkModeDisabled } = result.data;
|
||||
const { css, cssVars, darkModeDisabled, language } = result.data;
|
||||
|
||||
if (darkModeDisabled) {
|
||||
document.documentElement.classList.add('dark-mode-disabled');
|
||||
|
|
@ -70,11 +76,28 @@ export default function AuthoringLayout() {
|
|||
cssVars,
|
||||
});
|
||||
}
|
||||
|
||||
if (language && language !== APP_I18N_OPTIONS.sourceLang) {
|
||||
void dynamicActivate(language).finally(() => {
|
||||
setHasFinishedInit(true);
|
||||
});
|
||||
} else {
|
||||
setHasFinishedInit(true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
setHasFinishedInit(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (!hasFinishedInit) {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center">
|
||||
<Spinner />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!hasValidToken) {
|
||||
return (
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useLayoutEffect } from 'react';
|
||||
import { useLayoutEffect, useState } from 'react';
|
||||
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { OrganisationMemberRole, OrganisationType, TeamMemberRole } from '@prisma/client';
|
||||
|
|
@ -8,12 +8,15 @@ import { match } from 'ts-pattern';
|
|||
import { PAID_PLAN_LIMITS } from '@documenso/ee/server-only/limits/constants';
|
||||
import { LimitsProvider } from '@documenso/ee/server-only/limits/provider/client';
|
||||
import { OrganisationProvider } from '@documenso/lib/client-only/providers/organisation';
|
||||
import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n';
|
||||
import { verifyEmbeddingPresignToken } from '@documenso/lib/server-only/embedding-presign/verify-embedding-presign-token';
|
||||
import { getOrganisationClaimByTeamId } from '@documenso/lib/server-only/organisation/get-organisation-claims';
|
||||
import { getTeamSettings } from '@documenso/lib/server-only/team/get-team-settings';
|
||||
import { ZBaseEmbedDataSchema } from '@documenso/lib/types/embed-base-schemas';
|
||||
import { dynamicActivate } from '@documenso/lib/utils/i18n';
|
||||
import { TrpcProvider } from '@documenso/trpc/react';
|
||||
import type { OrganisationSession } from '@documenso/trpc/server/organisation-router/get-organisation-session.types';
|
||||
import { Spinner } from '@documenso/ui/primitives/spinner';
|
||||
|
||||
import { TeamProvider } from '~/providers/team';
|
||||
import { injectCss } from '~/utils/css-vars';
|
||||
|
|
@ -60,6 +63,8 @@ export const loader = async ({ request }: Route.LoaderArgs) => {
|
|||
export default function AuthoringLayout() {
|
||||
const { token, teamId, organisationClaim, preferences } = useLoaderData<typeof loader>();
|
||||
|
||||
const [hasFinishedInit, setHasFinishedInit] = useState(false);
|
||||
|
||||
const allowEmbedAuthoringWhiteLabel = organisationClaim.flags.embedAuthoringWhiteLabel ?? false;
|
||||
|
||||
useLayoutEffect(() => {
|
||||
|
|
@ -69,10 +74,11 @@ export default function AuthoringLayout() {
|
|||
const result = ZBaseEmbedDataSchema.safeParse(JSON.parse(decodeURIComponent(atob(hash))));
|
||||
|
||||
if (!result.success) {
|
||||
setHasFinishedInit(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const { css, cssVars, darkModeDisabled } = result.data;
|
||||
const { css, cssVars, darkModeDisabled, language } = result.data;
|
||||
|
||||
if (darkModeDisabled) {
|
||||
document.documentElement.classList.add('dark-mode-disabled');
|
||||
|
|
@ -84,8 +90,17 @@ export default function AuthoringLayout() {
|
|||
cssVars,
|
||||
});
|
||||
}
|
||||
|
||||
if (language && language !== APP_I18N_OPTIONS.sourceLang) {
|
||||
void dynamicActivate(language).finally(() => {
|
||||
setHasFinishedInit(true);
|
||||
});
|
||||
} else {
|
||||
setHasFinishedInit(true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
setHasFinishedInit(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
|
@ -139,7 +154,13 @@ export default function AuthoringLayout() {
|
|||
}}
|
||||
teamId={team.id}
|
||||
>
|
||||
<Outlet />
|
||||
{hasFinishedInit ? (
|
||||
<Outlet />
|
||||
) : (
|
||||
<div className="flex min-h-screen items-center justify-center">
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
</LimitsProvider>
|
||||
</TrpcProvider>
|
||||
</TeamProvider>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
import type { MessageDescriptor } from '@lingui/core';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { SUPPORTED_LANGUAGE_CODES, type SupportedLanguageCodes } from './locales';
|
||||
|
||||
export * from './locales';
|
||||
|
||||
export const ZSupportedLanguageCodeSchema = z.enum(SUPPORTED_LANGUAGE_CODES).catch('en');
|
||||
|
||||
export type I18nLocaleData = {
|
||||
/**
|
||||
* The supported language extracted from the locale.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export const SUPPORTED_LANGUAGE_CODES = [
|
||||
'de',
|
||||
'en',
|
||||
|
|
@ -19,3 +21,5 @@ export const APP_I18N_OPTIONS = {
|
|||
sourceLang: 'en',
|
||||
defaultLocale: 'en-US',
|
||||
} as const;
|
||||
|
||||
export const ZSupportedLanguageCodeSchema = z.enum(SUPPORTED_LANGUAGE_CODES).catch('en');
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { ZSupportedLanguageCodeSchema } from '@documenso/lib/constants/locales';
|
||||
|
||||
import { ZCssVarsSchema } from './css-vars';
|
||||
|
||||
export const ZBaseEmbedDataSchema = z.object({
|
||||
|
|
@ -9,4 +11,5 @@ export const ZBaseEmbedDataSchema = z.object({
|
|||
.optional()
|
||||
.transform((value) => value || undefined),
|
||||
cssVars: ZCssVarsSchema.optional().default({}),
|
||||
language: ZSupportedLanguageCodeSchema.optional(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ export const DocumentGlobalAuthAccessTooltip = () => (
|
|||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="text-foreground max-w-md space-y-2 p-4">
|
||||
<TooltipContent className="max-w-md space-y-2 p-4 text-foreground">
|
||||
<h2>
|
||||
<strong>
|
||||
<Trans>Document access</Trans>
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ export const DocumentGlobalAuthActionTooltip = () => (
|
|||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="text-foreground max-w-md space-y-2 p-4">
|
||||
<TooltipContent className="max-w-md space-y-2 p-4 text-foreground">
|
||||
<h2>
|
||||
<Trans>Global recipient action authentication</Trans>
|
||||
</h2>
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export const DocumentVisibilityTooltip = () => {
|
|||
<InfoIcon className="mx-2 h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="text-foreground max-w-md space-y-2 p-4">
|
||||
<TooltipContent className="max-w-md space-y-2 p-4 text-foreground">
|
||||
<h2>
|
||||
<strong>
|
||||
<Trans>Document visibility</Trans>
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ export const RecipientActionAuthSelect = ({
|
|||
<InfoIcon className="h-4 w-4" />
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent className="text-foreground max-w-md p-4">
|
||||
<TooltipContent className="max-w-md p-4 text-foreground">
|
||||
<h2>
|
||||
<strong>
|
||||
<Trans>Recipient action authentication</Trans>
|
||||
|
|
|
|||
|
|
@ -104,10 +104,10 @@ export const FieldSelector = ({
|
|||
)}
|
||||
>
|
||||
<CardContent className="relative flex items-center justify-center gap-x-2 px-6 py-4">
|
||||
{Icon && <Icon className="text-muted-foreground h-4 w-4" />}
|
||||
{Icon && <Icon className="h-4 w-4 text-muted-foreground" />}
|
||||
<span
|
||||
className={cn(
|
||||
'text-muted-foreground group-data-[selected]:text-foreground text-sm',
|
||||
'text-sm text-muted-foreground group-data-[selected]:text-foreground',
|
||||
field.type === FieldType.SIGNATURE && 'invisible',
|
||||
)}
|
||||
>
|
||||
|
|
@ -115,7 +115,7 @@ export const FieldSelector = ({
|
|||
</span>
|
||||
|
||||
{field.type === FieldType.SIGNATURE && (
|
||||
<div className="text-muted-foreground font-signature absolute inset-0 flex items-center justify-center text-lg">
|
||||
<div className="absolute inset-0 flex items-center justify-center font-signature text-lg text-muted-foreground">
|
||||
<Trans>Signature</Trans>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Reference in a new issue