exp: millionjs on marketing page

This commit is contained in:
Ephraim Atta-Duncan
2024-01-20 14:22:24 +00:00
parent 204388888d
commit a01385b15f
24 changed files with 529 additions and 110 deletions

View File

@ -1,3 +1,4 @@
const million = require('million/compiler');
/* eslint-disable @typescript-eslint/no-var-requires */
const fs = require('fs');
const path = require('path');
@ -5,11 +6,11 @@ const { withContentlayer } = require('next-contentlayer');
const ENV_FILES = ['.env', '.env.local', `.env.${process.env.NODE_ENV || 'development'}`];
ENV_FILES.forEach((file) => {
for (file of ENV_FILES) {
require('dotenv').config({
path: path.join(__dirname, `../../${file}`),
});
});
}
// !: This is a temp hack to get caveat working without placing it back in the public directory.
// !: By inlining this at build time we should be able to sign faster.
@ -94,4 +95,6 @@ const config = {
},
};
module.exports = withContentlayer(config);
module.exports = million.next(
withContentlayer(config), { auto: { rsc: true } }
);

View File

@ -24,6 +24,7 @@
"lucide-react": "^0.279.0",
"luxon": "^3.4.0",
"micro": "^10.0.1",
"million": "^2.6.4",
"next": "14.0.3",
"next-auth": "4.24.5",
"next-contentlayer": "^0.3.4",

View File

@ -20,7 +20,7 @@ export const generateMetadata = ({ params }: { params: { content: string } }) =>
const mdxComponents: MDXComponents = {
MdxNextImage: (props: { width: number; height: number; alt?: string; src: string }) => (
<Image {...props} alt={props.alt ?? ''} />
<Image width={props.width} height={props.height} src={props.src} alt={props.alt ?? ''} />
),
};

View File

@ -25,7 +25,7 @@ export const generateMetadata = ({ params }: { params: { post: string } }) => {
const mdxComponents: MDXComponents = {
MdxNextImage: (props: { width: number; height: number; alt?: string; src: string }) => (
<Image {...props} alt={props.alt ?? ''} />
<Image width={props.width} height={props.height} src={props.src} alt={props.alt ?? ''} />
),
};

View File

@ -1,6 +1,6 @@
'use client';
import { HTMLAttributes } from 'react';
import type { HTMLAttributes } from 'react';
import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
@ -24,7 +24,6 @@ export const BarMetric = <T extends Record<string, Record<keyof T[string], unkno
label,
chartHeight = 400,
extraInfo,
...props
}: BarMetricProps<T>) => {
const formattedData = Object.keys(data)
.map((key) => ({
@ -34,7 +33,7 @@ export const BarMetric = <T extends Record<string, Record<keyof T[string], unkno
.reverse();
return (
<div className={cn('flex flex-col', className)} {...props}>
<div className={cn('flex flex-col', className)}>
<div className="flex items-center px-4">
<h3 className="text-lg font-semibold">{title}</h3>
<span>{extraInfo}</span>

View File

@ -1,6 +1,7 @@
'use client';
import { HTMLAttributes, useEffect, useState } from 'react';
import type { HTMLAttributes } from 'react';
import { useEffect, useState } from 'react';
import { Cell, Legend, Pie, PieChart, Tooltip } from 'recharts';
@ -41,14 +42,14 @@ const renderCustomizedLabel = ({
export type CapTableProps = HTMLAttributes<HTMLDivElement>;
export const CapTable = ({ className, ...props }: CapTableProps) => {
export const CapTable = ({ className }: CapTableProps) => {
const [isSSR, setIsSSR] = useState(true);
useEffect(() => {
setIsSSR(false);
}, []);
return (
<div className={cn('flex flex-col', className)} {...props}>
<div className={cn('flex flex-col', className)}>
<h3 className="px-4 text-lg font-semibold">Cap Table</h3>
<div className="border-border mt-2.5 flex flex-1 items-center justify-center rounded-2xl border shadow-sm hover:shadow">
@ -76,7 +77,7 @@ export const CapTable = ({ className, ...props }: CapTableProps) => {
/>
<Tooltip
formatter={(percent: number, name, props) => {
return [`${percent}%`, name || props['name'] || props['payload']['name']];
return [`${percent}%`, name || props.name || props.payload.name];
}}
/>
</PieChart>

View File

@ -1,6 +1,6 @@
'use client';
import { HTMLAttributes } from 'react';
import type { HTMLAttributes } from 'react';
import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
@ -11,14 +11,14 @@ export type FundingRaisedProps = HTMLAttributes<HTMLDivElement> & {
data: Record<string, string | number>[];
};
export const FundingRaised = ({ className, data, ...props }: FundingRaisedProps) => {
export const FundingRaised = ({ className, data }: FundingRaisedProps) => {
const formattedData = data.map((item) => ({
amount: Number(item.amount),
date: formatMonth(item.date as string),
}));
return (
<div className={cn('flex flex-col', className)} {...props}>
<div className={cn('flex flex-col', className)}>
<h3 className="px-4 text-lg font-semibold">Total Funding Raised</h3>
<div className="border-border mt-2.5 flex flex-1 flex-col items-center justify-center rounded-2xl border p-6 pl-2 pt-12 shadow-sm hover:shadow">

View File

@ -1,4 +1,4 @@
import { HTMLAttributes } from 'react';
import type { HTMLAttributes } from 'react';
import { cn } from '@documenso/ui/lib/utils';
@ -7,9 +7,9 @@ export type MetricCardProps = HTMLAttributes<HTMLDivElement> & {
value: string;
};
export const MetricCard = ({ className, title, value, ...props }: MetricCardProps) => {
export const MetricCard = ({ className, title, value }: MetricCardProps) => {
return (
<div className={cn('rounded-md border p-4 shadow-sm hover:shadow', className)} {...props}>
<div className={cn('rounded-md border p-4 shadow-sm hover:shadow', className)}>
<h4 className="text-muted-foreground text-sm font-medium">{title}</h4>
<p className="mb-2 mt-6 text-4xl font-bold">{value}</p>

View File

@ -141,7 +141,12 @@ export default async function OpenPage() {
<p className="text-muted-foreground mt-4 max-w-[60ch] text-center text-lg leading-normal">
All our metrics, finances, and learnings are public. We believe in transparency and want
to share our journey with you. You can read more about why here:{' '}
<a className="font-bold" href="https://documenso.com/blog/pre-seed" target="_blank">
<a
className="font-bold"
href="https://documenso.com/blog/pre-seed"
target="_blank"
rel="noreferrer"
>
Announcing Open Metrics
</a>
</p>

View File

@ -1,4 +1,4 @@
import { HTMLAttributes } from 'react';
import type { HTMLAttributes } from 'react';
import { cn } from '@documenso/ui/lib/utils';
import {
@ -14,9 +14,9 @@ import { SALARY_BANDS } from '~/app/(marketing)/open/data';
export type SalaryBandsProps = HTMLAttributes<HTMLDivElement>;
export const SalaryBands = ({ className, ...props }: SalaryBandsProps) => {
export const SalaryBands = ({ className }: SalaryBandsProps) => {
return (
<div className={cn('flex flex-col', className)} {...props}>
<div className={cn('flex flex-col', className)}>
<h3 className="px-4 text-lg font-semibold">Global Salary Bands</h3>
<div className="border-border mt-2.5 flex-1 rounded-2xl border shadow-sm hover:shadow">
@ -30,7 +30,7 @@ export const SalaryBands = ({ className, ...props }: SalaryBandsProps) => {
</TableHeader>
<TableBody>
{SALARY_BANDS.map((band, index) => (
<TableRow key={index}>
<TableRow key={band.title + index.toString()}>
<TableCell className="font-medium">{band.title}</TableCell>
<TableCell>{band.seniority}</TableCell>
<TableCell className="text-right">

View File

@ -1,4 +1,4 @@
import { HTMLAttributes } from 'react';
import type { HTMLAttributes } from 'react';
import { cn } from '@documenso/ui/lib/utils';
import {
@ -14,9 +14,9 @@ import { TEAM_MEMBERS } from './data';
export type TeamMembersProps = HTMLAttributes<HTMLDivElement>;
export const TeamMembers = ({ className, ...props }: TeamMembersProps) => {
export const TeamMembers = ({ className }: TeamMembersProps) => {
return (
<div className={cn('flex flex-col', className)} {...props}>
<div className={cn('flex flex-col', className)}>
<h2 className="px-4 text-2xl font-semibold">Team</h2>
<div className="border-border mt-2.5 flex-1 rounded-2xl border shadow-sm hover:shadow">

View File

@ -34,13 +34,7 @@ export const ConfettiScreen = ({
}
return createPortal(
<Confetti
{...props}
className="w-full"
numberOfPieces={numberOfPieces}
width={width}
height={height}
/>,
<Confetti className="w-full" numberOfPieces={numberOfPieces} width={width} height={height} />,
document.body,
);
};

View File

@ -1,4 +1,4 @@
import { HTMLAttributes } from 'react';
import type { HTMLAttributes } from 'react';
import Image from 'next/image';
@ -11,12 +11,9 @@ import { Card, CardContent } from '@documenso/ui/primitives/card';
export type FasterSmarterBeautifulBentoProps = HTMLAttributes<HTMLDivElement>;
export const FasterSmarterBeautifulBento = ({
className,
...props
}: FasterSmarterBeautifulBentoProps) => {
export const FasterSmarterBeautifulBento = ({ className }: FasterSmarterBeautifulBentoProps) => {
return (
<div className={cn('relative', className)} {...props}>
<div className={cn('relative', className)}>
<div className="absolute inset-0 -z-10 flex items-center justify-center">
<Image
src={backgroundPattern}

View File

@ -35,9 +35,9 @@ const FOOTER_LINKS = [
{ href: '/privacy', text: 'Privacy' },
];
export const Footer = ({ className, ...props }: FooterProps) => {
export const Footer = ({ className }: FooterProps) => {
return (
<div className={cn('border-t py-12', className)} {...props}>
<div className={cn('border-t py-12', className)}>
<div className="mx-auto flex w-full max-w-screen-xl flex-wrap items-start justify-between gap-8 px-8">
<div className="flex-shrink-0">
<Link href="/">
@ -53,7 +53,7 @@ export const Footer = ({ className, ...props }: FooterProps) => {
<div className="mt-4 flex flex-wrap items-center gap-x-4 gap-y-4">
{SOCIAL_LINKS.map((link, index) => (
<Link
key={index}
key={link.href + index.toString()}
href={link.href}
target="_blank"
className="text-muted-foreground hover:text-muted-foreground/80"
@ -67,7 +67,7 @@ export const Footer = ({ className, ...props }: FooterProps) => {
<div className="grid w-full max-w-sm grid-cols-2 gap-x-4 gap-y-2 md:w-auto md:gap-x-8">
{FOOTER_LINKS.map((link, index) => (
<Link
key={index}
key={link.href + index.toString()}
href={link.href}
target={link.target}
className="text-muted-foreground hover:text-muted-foreground/80 flex-shrink-0 break-words text-sm"

View File

@ -15,7 +15,7 @@ import { MobileNavigation } from './mobile-navigation';
export type HeaderProps = HTMLAttributes<HTMLElement>;
export const Header = ({ className, ...props }: HeaderProps) => {
export const Header = ({ className }: HeaderProps) => {
const [isHamburgerMenuOpen, setIsHamburgerMenuOpen] = useState(false);
const { getFlag } = useFeatureFlags();
@ -23,7 +23,7 @@ export const Header = ({ className, ...props }: HeaderProps) => {
const isSinglePlayerModeMarketingEnabled = getFlag('marketing_header_single_player_mode');
return (
<header className={cn('flex items-center justify-between', className)} {...props}>
<header className={cn('flex items-center justify-between', className)}>
<div className="flex items-center space-x-4">
<Link href="/" className="z-10" onClick={() => setIsHamburgerMenuOpen(false)}>
<Image

View File

@ -3,7 +3,8 @@
import Image from 'next/image';
import Link from 'next/link';
import { Variants, motion } from 'framer-motion';
import type { Variants } from 'framer-motion';
import { motion } from 'framer-motion';
import { usePlausible } from 'next-plausible';
import { LuGithub } from 'react-icons/lu';
import { match } from 'ts-pattern';
@ -49,7 +50,7 @@ const HeroTitleVariants: Variants = {
},
};
export const Hero = ({ className, ...props }: HeroProps) => {
export const Hero = ({ className }: HeroProps) => {
const event = usePlausible();
const { getFlag } = useFeatureFlags();
@ -74,7 +75,7 @@ export const Hero = ({ className, ...props }: HeroProps) => {
};
return (
<motion.div className={cn('relative', className)} {...props}>
<motion.div className={cn('relative', className)}>
<div className="absolute -inset-24 -z-10">
<motion.div
className="flex h-full w-full origin-top-right items-center justify-center"

View File

@ -1,4 +1,4 @@
import { HTMLAttributes } from 'react';
import type { HTMLAttributes } from 'react';
import Image from 'next/image';
@ -11,9 +11,9 @@ import { Card, CardContent } from '@documenso/ui/primitives/card';
export type OpenBuildTemplateBentoProps = HTMLAttributes<HTMLDivElement>;
export const OpenBuildTemplateBento = ({ className, ...props }: OpenBuildTemplateBentoProps) => {
export const OpenBuildTemplateBento = ({ className }: OpenBuildTemplateBentoProps) => {
return (
<div className={cn('relative', className)} {...props}>
<div className={cn('relative', className)}>
<div className="absolute inset-0 -z-10 flex items-center justify-center">
<Image
src={backgroundPattern}

View File

@ -15,13 +15,13 @@ export type PricingTableProps = HTMLAttributes<HTMLDivElement>;
const SELECTED_PLAN_BAR_LAYOUT_ID = 'selected-plan-bar';
export const PricingTable = ({ className, ...props }: PricingTableProps) => {
export const PricingTable = ({ className }: PricingTableProps) => {
const event = usePlausible();
const [period, setPeriod] = useState<'MONTHLY' | 'YEARLY'>('MONTHLY');
return (
<div className={cn('', className)} {...props}>
<div className={cn('', className)}>
<div className="flex items-center justify-center gap-x-6">
<AnimatePresence>
<motion.button

View File

@ -1,4 +1,4 @@
import { HTMLAttributes } from 'react';
import type { HTMLAttributes } from 'react';
import Image from 'next/image';
@ -12,12 +12,9 @@ import { Card, CardContent } from '@documenso/ui/primitives/card';
export type ShareConnectPaidWidgetBentoProps = HTMLAttributes<HTMLDivElement>;
export const ShareConnectPaidWidgetBento = ({
className,
...props
}: ShareConnectPaidWidgetBentoProps) => {
export const ShareConnectPaidWidgetBento = ({ className }: ShareConnectPaidWidgetBentoProps) => {
return (
<div className={cn('relative', className)} {...props}>
<div className={cn('relative', className)}>
<div className="absolute inset-0 -z-10 flex items-center justify-center">
<Image
src={backgroundPattern}

View File

@ -55,7 +55,7 @@ type StepValues = (typeof STEP)[StepKeys];
export type WidgetProps = HTMLAttributes<HTMLDivElement>;
export const Widget = ({ className, children, ...props }: WidgetProps) => {
export const Widget = ({ className, children }: WidgetProps) => {
const { toast } = useToast();
const event = usePlausible();
@ -148,19 +148,19 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
const claimPlanInput = signatureDataUrl
? {
name,
email,
planId,
signatureDataUrl: signatureDataUrl,
signatureText: null,
}
name,
email,
planId,
signatureDataUrl: signatureDataUrl,
signatureText: null,
}
: {
name,
email,
planId,
signatureDataUrl: null,
signatureText: signatureText ?? '',
};
name,
email,
planId,
signatureDataUrl: null,
signatureText: signatureText ?? '',
};
const [result] = await Promise.all([claimPlan(claimPlanInput), delay]);
@ -183,7 +183,6 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
<Card
className={cn('mx-auto w-full max-w-4xl rounded-3xl before:rounded-3xl', className)}
gradient
{...props}
>
<div className="grid grid-cols-12 gap-y-8 overflow-hidden p-2 lg:gap-x-8">
<div className="text-muted-foreground col-span-12 flex flex-col gap-y-4 p-4 text-xs leading-relaxed lg:col-span-7">

View File

@ -1,4 +1,4 @@
import { SVGAttributes } from 'react';
import type { SVGAttributes } from 'react';
export type BackgroundProps = Omit<SVGAttributes<SVGElement>, 'viewBox'>;

View File

@ -3,7 +3,7 @@
import * as React from 'react';
import { ThemeProvider as NextThemesProvider } from 'next-themes';
import { ThemeProviderProps } from 'next-themes/dist/types';
import type { ThemeProviderProps } from 'next-themes/dist/types';
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;