feat: templates (#537)

Adds the basically ability to create and use templates for repetitive document types
This commit is contained in:
Lucas Smith
2023-12-21 22:05:09 +11:00
committed by GitHub
51 changed files with 2688 additions and 34 deletions

View File

@ -3,6 +3,9 @@
import type { HTMLAttributes } from 'react';
import { useEffect, useState } from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { Search } from 'lucide-react';
import { cn } from '@documenso/ui/lib/utils';
@ -10,10 +13,22 @@ import { Button } from '@documenso/ui/primitives/button';
import { CommandMenu } from '../common/command-menu';
const navigationLinks = [
{
href: '/documents',
label: 'Documents',
},
{
href: '/templates',
label: 'Templates',
},
];
export type DesktopNavProps = HTMLAttributes<HTMLDivElement>;
export const DesktopNav = ({ className, ...props }: DesktopNavProps) => {
// const pathname = usePathname();
const pathname = usePathname();
const [open, setOpen] = useState(false);
const [modifierKey, setModifierKey] = useState(() => 'Ctrl');
@ -26,9 +41,29 @@ export const DesktopNav = ({ className, ...props }: DesktopNavProps) => {
return (
<div
className={cn('ml-8 hidden flex-1 gap-x-6 md:flex md:justify-center', className)}
className={cn(
'ml-8 hidden flex-1 items-center gap-x-12 md:flex md:justify-between',
className,
)}
{...props}
>
<div className="flex items-baseline gap-x-6">
{navigationLinks.map(({ href, label }) => (
<Link
key={href}
href={href}
className={cn(
'text-muted-foreground dark:text-muted focus-visible:ring-ring ring-offset-background rounded-md font-medium leading-5 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2',
{
'text-foreground dark:text-muted-foreground': pathname?.startsWith(href),
},
)}
>
{label}
</Link>
))}
</div>
<CommandMenu open={open} onOpenChange={setOpen} />
<Button
@ -47,19 +82,6 @@ export const DesktopNav = ({ className, ...props }: DesktopNavProps) => {
</div>
</div>
</Button>
{/* We have no other subpaths rn */}
{/* <Link
href="/documents"
className={cn(
'text-muted-foreground focus-visible:ring-ring ring-offset-background rounded-md font-medium leading-5 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2',
{
'text-foreground': pathname?.startsWith('/documents'),
},
)}
>
Documents
</Link> */}
</div>
);
};

View File

@ -49,7 +49,7 @@ export const Header = ({ className, user, ...props }: HeaderProps) => {
<DesktopNav />
<div className="flex gap-x-4">
<div className="flex gap-x-4 md:ml-8">
<ProfileDropdown user={user} />
{/* <Button variant="outline" size="sm" className="h-10 w-10 p-0.5 md:hidden">

View File

@ -4,6 +4,7 @@ import Link from 'next/link';
import {
CreditCard,
FileSpreadsheet,
Lock,
LogOut,
User as LucideUser,
@ -106,6 +107,13 @@ export const ProfileDropdown = ({ user }: ProfileDropdownProps) => {
</DropdownMenuItem>
)}
<DropdownMenuSeparator />
<DropdownMenuItem asChild>
<Link href="/templates" className="cursor-pointer">
<FileSpreadsheet className="mr-2 h-4 w-4" />
Templates
</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuSub>

View File

@ -0,0 +1,50 @@
import { HTMLAttributes } from 'react';
import { Globe, Lock } from 'lucide-react';
import type { LucideIcon } from 'lucide-react/dist/lucide-react';
import { TemplateType as TemplateTypePrisma } from '@documenso/prisma/client';
import { cn } from '@documenso/ui/lib/utils';
type TemplateTypeIcon = {
label: string;
icon?: LucideIcon;
color: string;
};
type TemplateTypes = (typeof TemplateTypePrisma)[keyof typeof TemplateTypePrisma];
const TEMPLATE_TYPES: Record<TemplateTypes, TemplateTypeIcon> = {
PRIVATE: {
label: 'Private',
icon: Lock,
color: 'text-blue-600 dark:text-blue-300',
},
PUBLIC: {
label: 'Public',
icon: Globe,
color: 'text-green-500 dark:text-green-300',
},
};
export type TemplateTypeProps = HTMLAttributes<HTMLSpanElement> & {
type: TemplateTypes;
inheritColor?: boolean;
};
export const TemplateType = ({ className, type, inheritColor, ...props }: TemplateTypeProps) => {
const { label, icon: Icon, color } = TEMPLATE_TYPES[type];
return (
<span className={cn('flex items-center', className)} {...props}>
{Icon && (
<Icon
className={cn('mr-2 inline-block h-4 w-4', {
[color]: !inheritColor,
})}
/>
)}
{label}
</span>
);
};