Skip to content

Commit

Permalink
add pricing page
Browse files Browse the repository at this point in the history
  • Loading branch information
anuejn committed Nov 27, 2023
1 parent 906fb15 commit b3d3668
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 61 deletions.
14 changes: 10 additions & 4 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@ import { Metadata } from 'next';
import './globals.css';

export const metadata: Metadata = {
title: { absolute: "transcribee – The open source automatic transcription tool", template: "%s — transcribee" },
title: {
absolute: 'transcribee – The open source automatic transcription tool',
template: '%s — transcribee',
},
openGraph: {
title: { absolute: "transcribee – The open source automatic transcription tool", template: "%s — transcribee" },
title: {
absolute: 'transcribee – The open source automatic transcription tool',
template: '%s — transcribee',
},
description: 'The open source automatic transcription tool',
siteName: "transcribee",
siteName: 'transcribee',
},
}
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
Expand Down
58 changes: 35 additions & 23 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,34 @@ import ExportSrc from '../assets/export.png';
import CorrectSrc from '../assets/correct.png';
import clsx from 'clsx';



export default function HomePage() {
return (
<Page>
<Hero />
<Block
heading="State of the art automatic transcription."
imageSrc={WorkerPopupSrc}
imageAlt='An image of the transcribee popup showing the automatic transcription status'
imageAlt="An image of the transcribee popup showing the automatic transcription status"
>
transcribee uses the open source <i>Whisper</i> machine-learning (ML) model to create high quality automated transcriptions.
transcribee uses the open source <i>Whisper</i> machine-learning (ML) model to create high
quality automated transcriptions.
</Block>
<Block
heading="Manual Refinement"
imageSrc={CorrectSrc}
imageAlt='An image of the transcribee popup showing the automatic transcription status'
imageAlt="An image of the transcribee popup showing the automatic transcription status"
imageOnRight={true}
>
Automatic transcripts can easily be manually corrected. Words that are likely not correct are highlighted for speedy corrections.
Automatic transcripts can easily be manually corrected. Words that are likely not correct
are highlighted for speedy corrections.
</Block>
<Block
heading="Export"
imageSrc={ExportSrc}
imageAlt='An image of the transcribee popup showing the automatic transcription status'
imageAlt="An image of the transcribee popup showing the automatic transcription status"
>
Completed documents can be exported as Text documents or for subtitle usage as WebVTT or SRT.
Completed documents can be exported as Text documents or for subtitle usage as WebVTT or
SRT.
</Block>
<Block
heading="100% Open Source"
Expand All @@ -44,15 +45,16 @@ export default function HomePage() {
width: 1200,
height: 600,
}}
imageAlt=''
imageAlt=""
imageOnRight={true}
>
transcribee is open source and licensed under the AGPL-3.0 license. You can inspect the code, contribute to it and host your own instance. </Block>
transcribee is open source and licensed under the AGPL-3.0 license. You can inspect the
code, contribute to it and host your own instance.{' '}
</Block>
</Page>
);
}


function Hero() {
return (
<div className="flex flex-col md:flex-row gap-10 items-center my-6 sm:my-48">
Expand Down Expand Up @@ -89,7 +91,19 @@ function Hero() {
);
}

function Block({ children, heading, imageSrc, imageAlt, imageOnRight = false }: { children: ReactNode, heading: ReactNode, imageSrc: StaticImageData, imageAlt: string, imageOnRight?: boolean }) {
function Block({
children,
heading,
imageSrc,
imageAlt,
imageOnRight = false,
}: {
children: ReactNode;
heading: ReactNode;
imageSrc: StaticImageData;
imageAlt: string;
imageOnRight?: boolean;
}) {
return (
<div className="flex flex-col md:flex-row gap-10 items-center my-6 sm:my-36">
<div className="flex items-center">
Expand All @@ -99,17 +113,15 @@ function Block({ children, heading, imageSrc, imageAlt, imageOnRight = false }:
className="rounded-md w-[530px] shadow-[0px_1px_15px_rgba(0,0,0,0.1)]"
/>
</div>
<div className={clsx(
"text-center md:text-left items-center md:items-start flex flex-col flex-grow",
imageOnRight && 'md:order-first'
)}>
<h2 className="text-4xl font-semibold mb-6 leading-tight px-8 md:px-0">
{heading}
</h2>
<p className="text-lg leading-6 mb-6 max-w-sm">
{children}
</p>
<div
className={clsx(
'text-center md:text-left items-center md:items-start flex flex-col flex-grow',
imageOnRight && 'md:order-first',
)}
>
<h2 className="text-4xl font-semibold mb-6 leading-tight px-8 md:px-0">{heading}</h2>
<p className="text-lg leading-6 mb-6 max-w-sm">{children}</p>
</div>
</div>
)
);
}
118 changes: 114 additions & 4 deletions src/app/pricing/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,127 @@
import React, { ComponentProps, ReactNode } from 'react';
import { Metadata } from 'next';
import { Page } from '../../components/Page';
import clsx from 'clsx';
import Link from 'next/link';

export const metadata: Metadata = {
title: 'Pricing',
openGraph: {
title: 'Pricing'
}
}
title: 'Pricing',
},
};

export default function PricingPage() {
return (
<Page>
<h1>Pricing</h1>
<h1 className="text-center text-neutral-400 font-medium my-4">Pricing</h1>
<h2 className="text-center text-5xl font-semibold my-4">Predictable and Fair</h2>
<h3 className="text-center my-4">
Simple, yet affordable pricing model. Completely usage based. No monthly fees. No surprises.
</h3>
<div className="flex my-16">
<PricingCard title="Educational" buttonText="Request Discount" buttonUrl="/todo">
<Price price={1} />
<p>students and teachers only</p>
<hr className="h-px w-full my-1 bg-gray-200" />
<p>3 hours free each month</p>
<hr className="h-px w-full my-1 bg-gray-200" />
<p>$0.5/hour for lower quality transcripts</p>
</PricingCard>
<PricingCard
title="Regular"
buttonText="Get Started"
buttonUrl="https://transcribee.net/signup"
className="relative -mx-5 -my-3 z-10 h-[480px]"
>
<Price price={5} />
<p>commercial use</p>
<hr className="h-px w-full my-1 bg-gray-200" />
<p>3 hours free each month</p>
<hr className="h-px w-full my-1 bg-gray-200" />
<p>$2.5/hour for lower quality transcripts</p>
</PricingCard>
<PricingCard
title="Universities or Enterprises"
buttonText="Contact Us"
buttonUrl="/contact"
>
<div className="flex-grow" />

<div>
<p>You want a custom instance for your university or enterprise?</p>
<hr className="h-px w-full my-1 bg-gray-200" />
<p>You have special needs? </p>
<hr className="h-px w-full my-1 bg-gray-200" />
<p>You need custom features?</p>
</div>
</PricingCard>
</div>

<div className="flex my-16 gap-4">
<div className="rounded-md bg-neutral-100 p-10 basis-0 flex-grow">
<h3 className="text-2xl font-medium">Host it yourself</h3>
<p>
transcribee is 100% open source software. You can setup your own instance.{' '}
<b>No license costs apply.</b>
</p>
</div>
<div className="rounded-md bg-neutral-100 p-10 basis-0 flex-grow">
<h3 className="text-2xl font-medium">Non-profits</h3>
<p>
You’re making the world a better place?{' '}
<Link href="/contact" className="underline">
Contact us
</Link>
, we’ll see how we can support you.
</p>
</div>
</div>
</Page>
);
}

function PricingCard({
children,
title,
buttonText,
buttonUrl,
className,
}: {
children: ReactNode;
title: string;
buttonText: string;
buttonUrl: string;
className?: string;
}) {
return (
<div
className={clsx(
'border border-neutral-300 shadow-[0px_4px_20px_0px_rgba(0,0,0,0.15)] rounded-md border-solid flex-grow basis-0 h-[460px] flex flex-col p-14 items-center',
'bg-white',
className,
)}
>
<h3 className="text-center text-neutral-500 font-medium py-5">{title}</h3>
{children}
<div className="flex-grow" />
<a
href={buttonUrl}
className="inline-block bg-black hover:bg-gray-700 text-white px-4 py-2 rounded-md"
>
{buttonText}
</a>
</div>
);
}

function Price({ price }: { price: number }) {
return (
<div className="text-center pb-12">
<span className="text-2xl font-medium align-top"></span>
<span className="text-5xl font-bold">{price}</span>
<span className="text-5xl font-light">/hour</span>
<p className="text-neutral-500 font-medium">of transcribed audio</p>
</div>
);
}
76 changes: 46 additions & 30 deletions src/components/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ const NavLink = ({
className?: string;
} & ComponentProps<typeof Link>) => (
<li>
<Link href={href} className={clsx('text-gray-500 hover:text-black hover:underline', className)} {...props}>
<Link
href={href}
className={clsx('text-gray-500 hover:text-black hover:underline', className)}
{...props}
>
{children}
</Link>
</li>
Expand Down Expand Up @@ -73,7 +77,12 @@ function SidebarMenu() {
<FaBars className="w-full h-full" />
</label>

<input type="checkbox" name="" id="menu-checkbox" className="peer opacity-0 w-0 h-0 md:hidden" />
<input
type="checkbox"
name=""
id="menu-checkbox"
className="peer opacity-0 w-0 h-0 md:hidden"
/>
<div className="fixed flex flex-col right-0 top-0 bottom-0 bg-white p-4 shadow-lg border border-1 border-gray-200 transition-all duration-300 translate-x-[calc(100%+20px)] invisible peer-checked:visible peer-checked:translate-x-0 w-full sm:w-80">
<label
htmlFor="menu-checkbox"
Expand All @@ -100,48 +109,55 @@ function Navbar() {
);
}


function Footer({ }) {
function Footer({}) {
return (
<footer className='bg-neutral-100 py-12 px-10 mt-20'>
<div className='flex flex-row gap-5 flex-wrap max-w-7xl mx-auto px-4'>
<div className='flex-grow w-full sm:w-[unset]'>
<h2 className='font-bold text-lg place-content-evenly'>transcribee</h2>
<footer className="bg-neutral-100 py-12 px-10 mt-20">
<div className="flex flex-row gap-5 flex-wrap max-w-7xl mx-auto px-4">
<div className="flex-grow w-full sm:w-[unset]">
<h2 className="font-bold text-lg place-content-evenly">transcribee</h2>
</div>
<div className='flex-grow'>
<h3 className='font-semibold text-neutral-500'>Product</h3>
<ul className='mt-1'>
<NavLink href='/'>Features</NavLink>
<NavLink target="_blank" href='https://github.com/bugbakery/transcribee'>Github</NavLink>
<div className="flex-grow">
<h3 className="font-semibold text-neutral-500">Product</h3>
<ul className="mt-1">
<NavLink href="/">Features</NavLink>
<NavLink target="_blank" href="https://github.com/bugbakery/transcribee">
Github
</NavLink>
</ul>
</div>
<div className='flex-grow'>
<h3 className='font-semibold text-neutral-500'>Pricing</h3>
<ul className='mt-1'>
<NavLink href='/pricing'>Standard</NavLink>
<NavLink href='/pricing'>Educational</NavLink>
<NavLink href='/contact'>Contact Us</NavLink>
<div className="flex-grow">
<h3 className="font-semibold text-neutral-500">Pricing</h3>
<ul className="mt-1">
<NavLink href="/pricing">Standard</NavLink>
<NavLink href="/pricing">Educational</NavLink>
<NavLink href="/contact">Contact Us</NavLink>
</ul>
</div>
<div className='flex-grow'>
<h3 className='font-semibold text-neutral-500'>Legal</h3>
<ul className='mt-1'>
<NavLink target="_blank" href='https://transcribee.net/page/tos'>Terms of Service</NavLink>
<NavLink target="_blank" href='https://transcribee.net/page/privacy'>Privacy Policy</NavLink>
<NavLink target="_blank" href='/contact'>Imprint</NavLink>
<div className="flex-grow">
<h3 className="font-semibold text-neutral-500">Legal</h3>
<ul className="mt-1">
<NavLink target="_blank" href="https://transcribee.net/page/tos">
Terms of Service
</NavLink>
<NavLink target="_blank" href="https://transcribee.net/page/privacy">
Privacy Policy
</NavLink>
<NavLink target="_blank" href="/contact">
Imprint
</NavLink>
</ul>
</div>
</div>
</footer>
)
);
}

export function Page({ children }: { children: React.ReactNode }) {
export function Page({ children, className }: { children: React.ReactNode; className?: string }) {
return (
<div className='flex flex-col min-h-screen items-stretch place-content-stretch'>
<div className="flex flex-col min-h-screen items-stretch place-content-stretch">
<Navbar />
<main className="max-w-7xl mx-auto px-4">{children}</main>
<div className='flex-grow' />
<main className={clsx('max-w-7xl mx-auto px-4', className)}>{children}</main>
<div className="flex-grow" />
<Footer />
</div>
);
Expand Down

0 comments on commit b3d3668

Please sign in to comment.