Compare commits

..

4 Commits

Author SHA1 Message Date
2749520e10 fix: overflow workaround 2023-10-10 23:16:38 +11:00
8c023b092d fix: incorrect parameter 2023-10-10 15:05:14 +11:00
8d2badf75e fix: various items 2023-10-10 15:05:14 +11:00
9d6e149f56 refactor: update single player references 2023-10-10 15:05:14 +11:00
22 changed files with 85 additions and 135 deletions

View File

@ -1,55 +0,0 @@
tasks:
- init: |
npm i &&
npm run dx:up &&
cp .env.example .env &&
set -a; source .env &&
export NEXTAUTH_URL="$(gp url 3000)" &&
export NEXT_PUBLIC_WEBAPP_URL="$(gp url 3000)" &&
export NEXT_PUBLIC_MARKETING_URL="$(gp url 3001)"
command: npm run d
ports:
- port: 3000
visibility: public
onOpen: open-preview
- port: 3001
visibility: public
onOpen: open-preview
- port: 9000
visibility: public
onOpen: ignore
- port: 1100
visibility: private
onOpen: ignore
- port: 2500
visibility: private
onOpen: ignore
- port: 54320
visibility: private
onOpen: ignore
github:
prebuilds:
master: true
pullRequests: true
pullRequestsFromForks: true
addCheck: true
addComment: true
addBadge: true
vscode:
extensions:
- aaron-bond.better-comments
- bradlc.vscode-tailwindcss
- dbaeumer.vscode-eslint
- esbenp.prettier-vscode
- mikestead.dotenv
- unifiedjs.vscode-mdx
- GitHub.copilot-chat
- GitHub.copilot-labs
- GitHub.copilot
- GitHub.vscode-pull-request-github
- Prisma.prisma
- VisualStudioExptTeam.vscodeintellicode

View File

@ -2,6 +2,8 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { usePathname } from 'next/navigation';
import { cn } from '@documenso/ui/lib/utils'; import { cn } from '@documenso/ui/lib/utils';
import { Footer } from '~/components/(marketing)/footer'; import { Footer } from '~/components/(marketing)/footer';
@ -13,6 +15,7 @@ export type MarketingLayoutProps = {
export default function MarketingLayout({ children }: MarketingLayoutProps) { export default function MarketingLayout({ children }: MarketingLayoutProps) {
const [scrollY, setScrollY] = useState(0); const [scrollY, setScrollY] = useState(0);
const pathname = usePathname();
useEffect(() => { useEffect(() => {
const onScroll = () => { const onScroll = () => {
@ -25,7 +28,11 @@ export default function MarketingLayout({ children }: MarketingLayoutProps) {
}, []); }, []);
return ( return (
<div className="relative max-w-[100vw] overflow-y-auto overflow-x-hidden pt-20 md:pt-28"> <div
className={cn('relative max-w-[100vw] pt-20 md:pt-28', {
'overflow-y-auto overflow-x-hidden': pathname !== '/singleplayer',
})}
>
<div <div
className={cn('fixed left-0 top-0 z-50 w-full bg-transparent', { className={cn('fixed left-0 top-0 z-50 w-full bg-transparent', {
'bg-background/50 backdrop-blur-md': scrollY > 5, 'bg-background/50 backdrop-blur-md': scrollY > 5,

View File

@ -130,7 +130,7 @@ export default function SinglePlayerModePage() {
signer: data.email, signer: data.email,
}); });
router.push(`/single-player-mode/${documentToken}/success`); router.push(`/singleplayer/${documentToken}/success`);
} catch { } catch {
toast({ toast({
title: 'Something went wrong', title: 'Something went wrong',

View File

@ -4,7 +4,6 @@ import { Caveat, Inter } from 'next/font/google';
import { FeatureFlagProvider } from '@documenso/lib/client-only/providers/feature-flag'; import { FeatureFlagProvider } from '@documenso/lib/client-only/providers/feature-flag';
import { getAllAnonymousFlags } from '@documenso/lib/universal/get-feature-flag'; import { getAllAnonymousFlags } from '@documenso/lib/universal/get-feature-flag';
import { TrpcProvider } from '@documenso/trpc/react';
import { cn } from '@documenso/ui/lib/utils'; import { cn } from '@documenso/ui/lib/utils';
import { Toaster } from '@documenso/ui/primitives/toaster'; import { Toaster } from '@documenso/ui/primitives/toaster';
@ -64,9 +63,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
<body> <body>
<FeatureFlagProvider initialFlags={flags}> <FeatureFlagProvider initialFlags={flags}>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem> <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<PlausibleProvider> <PlausibleProvider>{children}</PlausibleProvider>
<TrpcProvider>{children}</TrpcProvider>
</PlausibleProvider>
</ThemeProvider> </ThemeProvider>
</FeatureFlagProvider> </FeatureFlagProvider>

View File

@ -23,7 +23,7 @@ const SOCIAL_LINKS = [
const FOOTER_LINKS = [ const FOOTER_LINKS = [
{ href: '/pricing', text: 'Pricing' }, { href: '/pricing', text: 'Pricing' },
{ href: '/single-player-mode', text: 'Single Player Mode' }, { href: '/singleplayer', text: 'Singleplayer' },
{ href: '/blog', text: 'Blog' }, { href: '/blog', text: 'Blog' },
{ href: '/open', text: 'Open' }, { href: '/open', text: 'Open' },
{ href: 'https://shop.documenso.com', text: 'Shop', target: '_blank' }, { href: 'https://shop.documenso.com', text: 'Shop', target: '_blank' },

View File

@ -35,7 +35,7 @@ export const Header = ({ className, ...props }: HeaderProps) => {
{isSinglePlayerModeMarketingEnabled && ( {isSinglePlayerModeMarketingEnabled && (
<Link <Link
href="/single-player-mode" href="/singleplayer"
className="bg-primary dark:text-background rounded-full px-2 py-1 text-xs font-semibold sm:px-3" className="bg-primary dark:text-background rounded-full px-2 py-1 text-xs font-semibold sm:px-3"
> >
Try now! Try now!

View File

@ -134,9 +134,9 @@ export const Hero = ({ className, ...props }: HeroProps) => {
variants={HeroTitleVariants} variants={HeroTitleVariants}
initial="initial" initial="initial"
animate="animate" animate="animate"
className="border-primary bg-background hover:bg-muted mx-auto mt-8 w-60 rounded-xl border transition duration-300" className="border-primary bg-background hover:bg-muted mx-auto mt-8 w-60 rounded-xl border transition-colors duration-300"
> >
<Link href="/single-player-mode" className="block px-4 py-2 text-center"> <Link href="/singleplayer" className="block px-4 py-2 text-center">
<h2 className="text-muted-foreground text-xs font-semibold"> <h2 className="text-muted-foreground text-xs font-semibold">
Introducing Single Player Mode Introducing Single Player Mode
</h2> </h2>

View File

@ -17,8 +17,8 @@ export type MobileNavigationProps = {
export const MENU_NAVIGATION_LINKS = [ export const MENU_NAVIGATION_LINKS = [
{ {
href: '/single-player-mode', href: '/singleplayer',
text: 'Single Player Mode', text: 'Singleplayer',
}, },
{ {
href: '/blog', href: '/blog',

View File

@ -1,8 +1,9 @@
'use client'; 'use client';
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
import { useToast } from '@documenso/ui/primitives/use-toast'; import { useToast } from '@documenso/ui/primitives/use-toast';
import { useCopyToClipboard } from '~/hooks/use-copy-to-clipboard';
export type PasswordRevealProps = { export type PasswordRevealProps = {
password: string; password: string;
}; };

View File

@ -4,13 +4,14 @@ import { useEffect, useState } from 'react';
import Link from 'next/link'; import Link from 'next/link';
import { Share } from 'lucide-react';
import { useFeatureFlags } from '@documenso/lib/client-only/providers/feature-flag'; import { useFeatureFlags } from '@documenso/lib/client-only/providers/feature-flag';
import { base64 } from '@documenso/lib/universal/base64'; import { base64 } from '@documenso/lib/universal/base64';
import { getFile } from '@documenso/lib/universal/upload/get-file'; import { getFile } from '@documenso/lib/universal/upload/get-file';
import { DocumentWithRecipient } from '@documenso/prisma/types/document-with-recipient'; import { DocumentWithRecipient } from '@documenso/prisma/types/document-with-recipient';
import DocumentDialog from '@documenso/ui/components/document/document-dialog'; import DocumentDialog from '@documenso/ui/components/document/document-dialog';
import { DocumentDownloadButton } from '@documenso/ui/components/document/document-download-button'; import { DocumentDownloadButton } from '@documenso/ui/components/document/document-download-button';
import { DocumentShareButton } from '@documenso/ui/components/document/document-share-button';
import { SigningCard3D } from '@documenso/ui/components/signing-card'; import { SigningCard3D } from '@documenso/ui/components/signing-card';
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';
@ -86,11 +87,11 @@ export const SinglePlayerModeSuccess = ({ className, document }: SinglePlayerMod
<div className="relative mt-8 w-full"> <div className="relative mt-8 w-full">
<div className={cn('flex flex-col items-center', className)}> <div className={cn('flex flex-col items-center', className)}>
<div className="grid w-full max-w-sm grid-cols-2 gap-4"> <div className="grid w-full max-w-sm grid-cols-2 gap-4">
<DocumentShareButton {/* TODO: Hook this up */}
documentId={document.id} <Button variant="outline" className="flex-1 bg-transparent backdrop-blur-sm" disabled>
token={document.Recipient.token} <Share className="mr-2 h-5 w-5" />
className="flex-1 bg-transparent backdrop-blur-sm" Share
/> </Button>
<DocumentDownloadButton <DocumentDownloadButton
className="flex-1 bg-transparent backdrop-blur-sm" className="flex-1 bg-transparent backdrop-blur-sm"
@ -102,7 +103,7 @@ export const SinglePlayerModeSuccess = ({ className, document }: SinglePlayerMod
<Button <Button
onClick={async () => onShowDocumentClick()} onClick={async () => onShowDocumentClick()}
loading={isFetchingDocumentFile} loading={isFetchingDocumentFile}
className="z-10 col-span-2" className="col-span-2"
> >
Show document Show document
</Button> </Button>

View File

@ -1,8 +0,0 @@
import * as trpcNext from '@documenso/trpc/server/adapters/next';
import { createTrpcContext } from '@documenso/trpc/server/context';
import { appRouter } from '@documenso/trpc/server/router';
export default trpcNext.createNextApiHandler({
router: appRouter,
createContext: async ({ req, res }) => createTrpcContext({ req, res }),
});

View File

@ -6,12 +6,13 @@ import { Edit, Pencil, Share } from 'lucide-react';
import { useSession } from 'next-auth/react'; import { useSession } from 'next-auth/react';
import { match } from 'ts-pattern'; import { match } from 'ts-pattern';
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
import { Document, DocumentStatus, Recipient, SigningStatus, User } from '@documenso/prisma/client'; import { Document, DocumentStatus, Recipient, SigningStatus, User } from '@documenso/prisma/client';
import { trpc } from '@documenso/trpc/react'; import { trpc } from '@documenso/trpc/react';
import { Button } from '@documenso/ui/primitives/button'; import { Button } from '@documenso/ui/primitives/button';
import { useToast } from '@documenso/ui/primitives/use-toast'; import { useToast } from '@documenso/ui/primitives/use-toast';
import { useCopyToClipboard } from '~/hooks/use-copy-to-clipboard';
export type DataTableActionButtonProps = { export type DataTableActionButtonProps = {
row: Document & { row: Document & {
User: Pick<User, 'id' | 'name' | 'email'>; User: Pick<User, 'id' | 'name' | 'email'>;
@ -46,7 +47,7 @@ export const DataTableActionButton = ({ row }: DataTableActionButtonProps) => {
documentId: row.id, documentId: row.id,
}); });
await copyToClipboard(`${process.env.NEXT_PUBLIC_WEBAPP_URL}/share/${slug}`).catch(() => null); await copyToClipboard(`${window.location.origin}/share/${slug}`).catch(() => null);
toast({ toast({
title: 'Copied to clipboard', title: 'Copied to clipboard',

View File

@ -18,7 +18,6 @@ import {
} from 'lucide-react'; } from 'lucide-react';
import { useSession } from 'next-auth/react'; import { useSession } from 'next-auth/react';
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
import { getFile } from '@documenso/lib/universal/upload/get-file'; import { getFile } from '@documenso/lib/universal/upload/get-file';
import { Document, DocumentStatus, Recipient, User } from '@documenso/prisma/client'; import { Document, DocumentStatus, Recipient, User } from '@documenso/prisma/client';
import { DocumentWithData } from '@documenso/prisma/types/document-with-data'; import { DocumentWithData } from '@documenso/prisma/types/document-with-data';
@ -33,6 +32,8 @@ import {
} from '@documenso/ui/primitives/dropdown-menu'; } from '@documenso/ui/primitives/dropdown-menu';
import { useToast } from '@documenso/ui/primitives/use-toast'; import { useToast } from '@documenso/ui/primitives/use-toast';
import { useCopyToClipboard } from '~/hooks/use-copy-to-clipboard';
import { DeleteDraftDocumentDialog } from './delete-draft-document-dialog'; import { DeleteDraftDocumentDialog } from './delete-draft-document-dialog';
export type DataTableActionDropdownProps = { export type DataTableActionDropdownProps = {
@ -72,7 +73,7 @@ export const DataTableActionDropdown = ({ row }: DataTableActionDropdownProps) =
documentId: row.id, documentId: row.id,
}); });
await copyToClipboard(`${process.env.NEXT_PUBLIC_WEBAPP_URL}/share/${slug}`).catch(() => null); await copyToClipboard(`${window.location.origin}/share/${slug}`).catch(() => null);
toast({ toast({
title: 'Copied to clipboard', title: 'Copied to clipboard',

View File

@ -9,11 +9,12 @@ import { getFieldsForToken } from '@documenso/lib/server-only/field/get-fields-f
import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token'; import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token';
import { DocumentStatus, FieldType } from '@documenso/prisma/client'; import { DocumentStatus, FieldType } from '@documenso/prisma/client';
import { DocumentDownloadButton } from '@documenso/ui/components/document/document-download-button'; import { DocumentDownloadButton } from '@documenso/ui/components/document/document-download-button';
import { DocumentShareButton } from '@documenso/ui/components/document/document-share-button';
import { SigningCard3D } from '@documenso/ui/components/signing-card'; import { SigningCard3D } from '@documenso/ui/components/signing-card';
import signingCelebration from '~/assets/signing-celebration.png'; import signingCelebration from '~/assets/signing-celebration.png';
import { ShareButton } from './share-button';
export type CompletedSigningPageProps = { export type CompletedSigningPageProps = {
params: { params: {
token?: string; token?: string;
@ -88,7 +89,7 @@ export default async function CompletedSigningPage({
))} ))}
<div className="mt-8 flex w-full max-w-sm items-center justify-center gap-4"> <div className="mt-8 flex w-full max-w-sm items-center justify-center gap-4">
<DocumentShareButton documentId={document.id} token={recipient.token} /> <ShareButton documentId={document.id} token={recipient.token} />
<DocumentDownloadButton <DocumentDownloadButton
className="flex-1" className="flex-1"

View File

@ -5,10 +5,8 @@ import { HTMLAttributes, useState } from 'react';
import { Copy, Share } from 'lucide-react'; import { Copy, Share } from 'lucide-react';
import { FaXTwitter } from 'react-icons/fa6'; import { FaXTwitter } from 'react-icons/fa6';
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
import { generateTwitterIntent } from '@documenso/lib/universal/generate-twitter-intent'; import { generateTwitterIntent } from '@documenso/lib/universal/generate-twitter-intent';
import { trpc } from '@documenso/trpc/react'; import { trpc } from '@documenso/trpc/react';
import { cn } from '@documenso/ui/lib/utils';
import { Button } from '@documenso/ui/primitives/button'; import { Button } from '@documenso/ui/primitives/button';
import { import {
Dialog, Dialog,
@ -20,12 +18,14 @@ import {
} from '@documenso/ui/primitives/dialog'; } from '@documenso/ui/primitives/dialog';
import { useToast } from '@documenso/ui/primitives/use-toast'; import { useToast } from '@documenso/ui/primitives/use-toast';
export type DocumentShareButtonProps = HTMLAttributes<HTMLButtonElement> & { import { useCopyToClipboard } from '~/hooks/use-copy-to-clipboard';
export type ShareButtonProps = HTMLAttributes<HTMLButtonElement> & {
token: string; token: string;
documentId: number; documentId: number;
}; };
export const DocumentShareButton = ({ token, documentId, className }: DocumentShareButtonProps) => { export const ShareButton = ({ token, documentId }: ShareButtonProps) => {
const { toast } = useToast(); const { toast } = useToast();
const [, copyToClipboard] = useCopyToClipboard(); const [, copyToClipboard] = useCopyToClipboard();
@ -60,7 +60,7 @@ export const DocumentShareButton = ({ token, documentId, className }: DocumentSh
slug = result.slug; slug = result.slug;
} }
await copyToClipboard(`${process.env.NEXT_PUBLIC_WEBAPP_URL}/share/${slug}`).catch(() => null); await copyToClipboard(`${window.location.origin}/share/${slug}`).catch(() => null);
toast({ toast({
title: 'Copied to clipboard', title: 'Copied to clipboard',
@ -85,7 +85,7 @@ export const DocumentShareButton = ({ token, documentId, className }: DocumentSh
window.open( window.open(
generateTwitterIntent( generateTwitterIntent(
`I just ${token ? 'signed' : 'sent'} a document with @documenso. Check it out!`, `I just ${token ? 'signed' : 'sent'} a document with @documenso. Check it out!`,
`${process.env.NEXT_PUBLIC_WEBAPP_URL}/share/${slug}`, `${window.location.origin}/share/${slug}`,
), ),
'_blank', '_blank',
); );
@ -99,7 +99,7 @@ export const DocumentShareButton = ({ token, documentId, className }: DocumentSh
<Button <Button
variant="outline" variant="outline"
disabled={!token || !documentId} disabled={!token || !documentId}
className={cn('flex-1', className)} className="flex-1"
loading={isLoading} loading={isLoading}
> >
{!isLoading && <Share className="mr-2 h-5 w-5" />} {!isLoading && <Share className="mr-2 h-5 w-5" />}
@ -120,12 +120,8 @@ export const DocumentShareButton = ({ token, documentId, className }: DocumentSh
<span className="font-medium text-blue-400">@documenso</span> <span className="font-medium text-blue-400">@documenso</span>
. Check it out! . Check it out!
<span className="mt-2 block" /> <span className="mt-2 block" />
<span <span className="break-all font-medium text-blue-400">
className={cn('break-all font-medium text-blue-400', { {window.location.origin}/share/{shareLink?.slug || '...'}
'animate-pulse': !shareLink?.slug,
})}
>
{process.env.NEXT_PUBLIC_WEBAPP_URL}/share/{shareLink?.slug || '...'}
</span> </span>
</div> </div>

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import { useEffect, useMemo, useState, useTransition } from 'react'; import { useMemo, useState, useTransition } from 'react';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
@ -48,7 +48,6 @@ export const SignatureField = ({ field, recipient }: SignatureFieldProps) => {
const [showSignatureModal, setShowSignatureModal] = useState(false); const [showSignatureModal, setShowSignatureModal] = useState(false);
const [localSignature, setLocalSignature] = useState<string | null>(null); const [localSignature, setLocalSignature] = useState<string | null>(null);
const [isLocalSignatureSet, setIsLocalSignatureSet] = useState(false);
const state = useMemo<SignatureFieldState>(() => { const state = useMemo<SignatureFieldState>(() => {
if (!field.inserted) { if (!field.inserted) {
@ -62,16 +61,9 @@ export const SignatureField = ({ field, recipient }: SignatureFieldProps) => {
return 'signed-text'; return 'signed-text';
}, [field.inserted, signature?.signatureImageAsBase64]); }, [field.inserted, signature?.signatureImageAsBase64]);
useEffect(() => {
if (!showSignatureModal && !isLocalSignatureSet) {
setLocalSignature(null);
}
}, [showSignatureModal, isLocalSignatureSet]);
const onSign = async (source: 'local' | 'provider' = 'provider') => { const onSign = async (source: 'local' | 'provider' = 'provider') => {
try { try {
if (!providedSignature && !localSignature) { if (!providedSignature && !localSignature) {
setIsLocalSignatureSet(false);
setShowSignatureModal(true); setShowSignatureModal(true);
return; return;
} }
@ -186,7 +178,6 @@ export const SignatureField = ({ field, recipient }: SignatureFieldProps) => {
disabled={!localSignature} disabled={!localSignature}
onClick={() => { onClick={() => {
setShowSignatureModal(false); setShowSignatureModal(false);
setIsLocalSignatureSet(true);
void onSign('local'); void onSign('local');
}} }}
> >

View File

@ -0,0 +1,28 @@
import { useState } from 'react';
export type CopiedValue = string | null;
export type CopyFn = (_text: string) => Promise<boolean>;
export function useCopyToClipboard(): [CopiedValue, CopyFn] {
const [copiedText, setCopiedText] = useState<CopiedValue>(null);
const copy: CopyFn = async (text) => {
if (!navigator?.clipboard) {
console.warn('Clipboard not supported');
return false;
}
// Try to save to clipboard then save it in the state if worked
try {
await navigator.clipboard.writeText(text);
setCopiedText(text);
return true;
} catch (error) {
console.warn('Copy failed', error);
setCopiedText(null);
return false;
}
};
return [copiedText, copy];
}

View File

@ -60,26 +60,17 @@ export const calculateTextScaleSize = (
*/ */
export function useElementScaleSize( export function useElementScaleSize(
container: { width: number; height: number }, container: { width: number; height: number },
child: RefObject<HTMLElement | null>, text: string,
fontSize: number, fontSize: number,
fontFamily: string, fontFamily: string,
) { ) {
const [scalingFactor, setScalingFactor] = useState(1); const [scalingFactor, setScalingFactor] = useState(1);
useEffect(() => { useEffect(() => {
if (!child.current) { const scaleSize = calculateTextScaleSize(container, text, `${fontSize}px`, fontFamily);
return;
}
const scaleSize = calculateTextScaleSize(
container,
child.current.innerText,
`${fontSize}px`,
fontFamily,
);
setScalingFactor(scaleSize); setScalingFactor(scaleSize);
}, [child, container, fontFamily, fontSize]); }, [text, container, fontFamily, fontSize]);
return scalingFactor; return scalingFactor;
} }

View File

@ -56,7 +56,7 @@ export const SigningCard3D = ({ className, name, signingCelebrationImage }: Sign
const sheenGradient = useMotionTemplate`linear-gradient( const sheenGradient = useMotionTemplate`linear-gradient(
30deg, 30deg,
transparent, transparent,
rgba(var(--sheen-color) / ${trackMouse ? sheenOpacity : 0}) ${sheenPosition}%, rgba(var(--sheen-color) / ${sheenOpacity}) ${sheenPosition}%,
transparent)`; transparent)`;
const cardRef = useRef<HTMLDivElement>(null); const cardRef = useRef<HTMLDivElement>(null);
@ -98,10 +98,12 @@ export const SigningCard3D = ({ className, name, signingCelebrationImage }: Sign
void animate(cardX, 0, { duration: 2, ease: 'backInOut' }); void animate(cardX, 0, { duration: 2, ease: 'backInOut' });
void animate(cardY, 0, { duration: 2, ease: 'backInOut' }); void animate(cardY, 0, { duration: 2, ease: 'backInOut' });
void animate(sheenOpacity, 0, { duration: 2, ease: 'backInOut' });
setTrackMouse(false); setTrackMouse(false);
}, 1000); }, 1000);
}, },
[cardX, cardY, cardCenterPosition, trackMouse], [cardX, cardY, cardCenterPosition, trackMouse, sheenOpacity],
); );
useEffect(() => { useEffect(() => {
@ -126,7 +128,6 @@ export const SigningCard3D = ({ className, name, signingCelebrationImage }: Sign
transformStyle: 'preserve-3d', transformStyle: 'preserve-3d',
rotateX, rotateX,
rotateY, rotateY,
// willChange: 'transform background-image',
}} }}
> >
<SigningCardContent className="bg-transparent" name={name} /> <SigningCardContent className="bg-transparent" name={name} />

View File

@ -70,25 +70,23 @@ export function SinglePlayerModeSignatureField({
throw new Error('Invalid field type'); throw new Error('Invalid field type');
} }
const $paragraphEl = useRef<HTMLParagraphElement>(null);
const { height, width } = useFieldPageCoords(field); const { height, width } = useFieldPageCoords(field);
const insertedBase64Signature = field.inserted && field.Signature?.signatureImageAsBase64;
const insertedTypeSignature = field.inserted && field.Signature?.typedSignature;
const scalingFactor = useElementScaleSize( const scalingFactor = useElementScaleSize(
{ {
height, height,
width, width,
}, },
$paragraphEl, insertedTypeSignature || '',
maxFontSize, maxFontSize,
fontVariableValue, fontVariableValue,
); );
const fontSize = maxFontSize * scalingFactor; const fontSize = maxFontSize * scalingFactor;
const insertedBase64Signature = field.inserted && field.Signature?.signatureImageAsBase64;
const insertedTypeSignature = field.inserted && field.Signature?.typedSignature;
return ( return (
<SinglePlayerModeFieldCardContainer field={field}> <SinglePlayerModeFieldCardContainer field={field}>
{insertedBase64Signature ? ( {insertedBase64Signature ? (
@ -99,7 +97,6 @@ export function SinglePlayerModeSignatureField({
/> />
) : insertedTypeSignature ? ( ) : insertedTypeSignature ? (
<p <p
ref={$paragraphEl}
style={{ style={{
fontSize: `clamp(${minFontSize}px, ${fontSize}px, ${maxFontSize}px)`, fontSize: `clamp(${minFontSize}px, ${fontSize}px, ${maxFontSize}px)`,
fontFamily: `var(${fontVariable})`, fontFamily: `var(${fontVariable})`,
@ -145,7 +142,7 @@ export function SinglePlayerModeCustomTextField({
height, height,
width, width,
}, },
$paragraphEl, field.customText,
maxFontSize, maxFontSize,
fontVariableValue, fontVariableValue,
); );