initial
@@ -0,0 +1,59 @@
|
||||
import { type Metadata } from 'next'
|
||||
import Link from 'next/link'
|
||||
|
||||
import { Button } from '@/components/Button'
|
||||
import { TextField } from '@/components/Fields'
|
||||
import { Logo } from '@/components/Logo'
|
||||
import { SlimLayout } from '@/components/SlimLayout'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Sign In',
|
||||
}
|
||||
|
||||
export default function Login() {
|
||||
return (
|
||||
<SlimLayout>
|
||||
<div className="flex">
|
||||
<Link href="/" aria-label="Home">
|
||||
<Logo className="h-10 w-auto" />
|
||||
</Link>
|
||||
</div>
|
||||
<h2 className="mt-20 text-lg font-semibold text-gray-900">
|
||||
Sign in to your account
|
||||
</h2>
|
||||
<p className="mt-2 text-sm text-gray-700">
|
||||
Don’t have an account?{' '}
|
||||
<Link
|
||||
href="/register"
|
||||
className="font-medium text-blue-600 hover:underline"
|
||||
>
|
||||
Sign up
|
||||
</Link>{' '}
|
||||
for a free trial.
|
||||
</p>
|
||||
<form action="#" className="mt-10 grid grid-cols-1 gap-y-8">
|
||||
<TextField
|
||||
label="Email address"
|
||||
name="email"
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
required
|
||||
/>
|
||||
<TextField
|
||||
label="Password"
|
||||
name="password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
required
|
||||
/>
|
||||
<div>
|
||||
<Button type="submit" variant="solid" color="blue" className="w-full">
|
||||
<span>
|
||||
Sign in <span aria-hidden="true">→</span>
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</SlimLayout>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import { type Metadata } from 'next'
|
||||
import Link from 'next/link'
|
||||
|
||||
import { Button } from '@/components/Button'
|
||||
import { SelectField, TextField } from '@/components/Fields'
|
||||
import { Logo } from '@/components/Logo'
|
||||
import { SlimLayout } from '@/components/SlimLayout'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Sign Up',
|
||||
}
|
||||
|
||||
export default function Register() {
|
||||
return (
|
||||
<SlimLayout>
|
||||
<div className="flex">
|
||||
<Link href="/" aria-label="Home">
|
||||
<Logo className="h-10 w-auto" />
|
||||
</Link>
|
||||
</div>
|
||||
<h2 className="mt-20 text-lg font-semibold text-gray-900">
|
||||
Get started for free
|
||||
</h2>
|
||||
<p className="mt-2 text-sm text-gray-700">
|
||||
Already registered?{' '}
|
||||
<Link
|
||||
href="/login"
|
||||
className="font-medium text-blue-600 hover:underline"
|
||||
>
|
||||
Sign in
|
||||
</Link>{' '}
|
||||
to your account.
|
||||
</p>
|
||||
<form
|
||||
action="#"
|
||||
className="mt-10 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-2"
|
||||
>
|
||||
<TextField
|
||||
label="First name"
|
||||
name="first_name"
|
||||
type="text"
|
||||
autoComplete="given-name"
|
||||
required
|
||||
/>
|
||||
<TextField
|
||||
label="Last name"
|
||||
name="last_name"
|
||||
type="text"
|
||||
autoComplete="family-name"
|
||||
required
|
||||
/>
|
||||
<TextField
|
||||
className="col-span-full"
|
||||
label="Email address"
|
||||
name="email"
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
required
|
||||
/>
|
||||
<TextField
|
||||
className="col-span-full"
|
||||
label="Password"
|
||||
name="password"
|
||||
type="password"
|
||||
autoComplete="new-password"
|
||||
required
|
||||
/>
|
||||
<SelectField
|
||||
className="col-span-full"
|
||||
label="How did you hear about us?"
|
||||
name="referral_source"
|
||||
>
|
||||
<option>AltaVista search</option>
|
||||
<option>Super Bowl commercial</option>
|
||||
<option>Our route 34 city bus ad</option>
|
||||
<option>The “Never Use This” podcast</option>
|
||||
</SelectField>
|
||||
<div className="col-span-full">
|
||||
<Button type="submit" variant="solid" color="blue" className="w-full">
|
||||
<span>
|
||||
Sign up <span aria-hidden="true">→</span>
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</SlimLayout>
|
||||
)
|
||||
}
|
||||
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,45 @@
|
||||
import { type Metadata } from 'next'
|
||||
import { Inter, Lexend } from 'next/font/google'
|
||||
import clsx from 'clsx'
|
||||
|
||||
import '@/styles/tailwind.css'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: {
|
||||
template: '%s - TaxPal',
|
||||
default: 'TaxPal - Accounting made simple for small businesses',
|
||||
},
|
||||
description:
|
||||
'Most bookkeeping software is accurate, but hard to use. We make the opposite trade-off, and hope you don’t get audited.',
|
||||
}
|
||||
|
||||
const inter = Inter({
|
||||
subsets: ['latin'],
|
||||
display: 'swap',
|
||||
variable: '--font-inter',
|
||||
})
|
||||
|
||||
const lexend = Lexend({
|
||||
subsets: ['latin'],
|
||||
display: 'swap',
|
||||
variable: '--font-lexend',
|
||||
})
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html
|
||||
lang="en"
|
||||
className={clsx(
|
||||
'h-full scroll-smooth bg-white antialiased',
|
||||
inter.variable,
|
||||
lexend.variable,
|
||||
)}
|
||||
>
|
||||
<body className="flex h-full flex-col">{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
import { Button } from '@/components/Button'
|
||||
import { Logo } from '@/components/Logo'
|
||||
import { SlimLayout } from '@/components/SlimLayout'
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<SlimLayout>
|
||||
<div className="flex">
|
||||
<Link href="/" aria-label="Home">
|
||||
<Logo className="h-10 w-auto" />
|
||||
</Link>
|
||||
</div>
|
||||
<p className="mt-20 text-sm font-medium text-gray-700">404</p>
|
||||
<h1 className="mt-3 text-lg font-semibold text-gray-900">
|
||||
Page not found
|
||||
</h1>
|
||||
<p className="mt-3 text-sm text-gray-700">
|
||||
Sorry, we couldn’t find the page you’re looking for.
|
||||
</p>
|
||||
<Button href="/" className="mt-10">
|
||||
Go back home
|
||||
</Button>
|
||||
</SlimLayout>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { type Metadata } from 'next'
|
||||
|
||||
import { Earnings } from '@/components/partner/Earnings'
|
||||
import { FinalCta } from '@/components/partner/FinalCta'
|
||||
import { Footer } from '@/components/partner/Footer'
|
||||
import { Header } from '@/components/partner/Header'
|
||||
import { Hero } from '@/components/partner/Hero'
|
||||
import { HowItWorks } from '@/components/partner/HowItWorks'
|
||||
import { Platform } from '@/components/partner/Platform'
|
||||
import { Problem } from '@/components/partner/Problem'
|
||||
import { Responsibilities } from '@/components/partner/Responsibilities'
|
||||
import { WhatIsUvi } from '@/components/partner/WhatIsUvi'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Partner-Modell - GebOS',
|
||||
description:
|
||||
'Mit GebOS erweitern Elektro- und Sanitärbetriebe ihr Angebot um einen monatlichen UVI- und Verbrauchserfassungsservice. Sie beraten und installieren, GebOS übernimmt Plattform, Datenverarbeitung und Abrechnung.',
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main>
|
||||
<Hero />
|
||||
<WhatIsUvi />
|
||||
<Problem />
|
||||
<Platform />
|
||||
{/* <HowItWorks /> */}
|
||||
<Responsibilities />
|
||||
<Earnings />
|
||||
<FinalCta />
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import { type Metadata } from 'next'
|
||||
import Link from 'next/link'
|
||||
|
||||
import { Container } from '@/components/Container'
|
||||
import { Footer } from '@/components/partner/Footer'
|
||||
import { Header } from '@/components/partner/Header'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Was ist UVI? - GebOS',
|
||||
description:
|
||||
'Die Unterjährige Verbrauchsinformation (UVI) erklärt: Was sie bedeutet, für wen sie gilt und welche Fristen ab 2027 zu beachten sind.',
|
||||
}
|
||||
|
||||
export default function WasIstUvi() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="py-20 sm:py-28">
|
||||
<Container className="max-w-3xl">
|
||||
<p className="text-sm font-semibold uppercase tracking-wide text-blue-600">
|
||||
Grundlagen
|
||||
</p>
|
||||
<h1 className="mt-3 font-display text-4xl tracking-tight text-slate-900 sm:text-5xl">
|
||||
Was ist UVI?
|
||||
</h1>
|
||||
|
||||
<div className="mt-8 space-y-6 text-lg leading-8 text-slate-700">
|
||||
<p>
|
||||
Die Unterjährige Verbrauchsinformation (UVI) ist eine regelmäßige
|
||||
Information für Mieter über ihren aktuellen Heiz- und
|
||||
Warmwasserverbrauch. Sie ersetzt nicht die jährliche
|
||||
Heizkostenabrechnung, sondern hilft Mietern, ihren Verbrauch schon
|
||||
während des Jahres besser zu verstehen und gegebenenfalls Energie
|
||||
zu sparen.
|
||||
</p>
|
||||
<p>
|
||||
Sind fernablesbare Messgeräte vorhanden, muss die UVI monatlich
|
||||
bereitgestellt werden. So sehen Mieter zeitnah, wie sich ihr
|
||||
Verhalten auf den Verbrauch auswirkt, statt erst mit der
|
||||
Jahresabrechnung.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-10 rounded-2xl border-l-4 border-blue-600 bg-blue-50/60 p-6">
|
||||
<p className="text-base text-slate-800">
|
||||
Ab 2027 müssen grundsätzlich alle Bestandsgeräte fernablesbar
|
||||
sein, da nicht fernablesbare Geräte bis{' '}
|
||||
<span className="font-semibold text-slate-900">31.12.2026</span>{' '}
|
||||
nachgerüstet oder ersetzt werden müssen.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-10">
|
||||
<Link
|
||||
href="/partner-modell#was-ist-uvi"
|
||||
className="text-sm font-semibold text-blue-600 hover:text-blue-500"
|
||||
>
|
||||
<span aria-hidden="true">←</span> Zurück zum Partner-Modell
|
||||
</Link>
|
||||
</div>
|
||||
</Container>
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import Link from 'next/link'
|
||||
import clsx from 'clsx'
|
||||
|
||||
const baseStyles = {
|
||||
solid:
|
||||
'group inline-flex items-center justify-center rounded-full py-2 px-4 text-sm font-semibold focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2',
|
||||
outline:
|
||||
'group inline-flex ring-1 items-center justify-center rounded-full py-2 px-4 text-sm focus:outline-none',
|
||||
}
|
||||
|
||||
const variantStyles = {
|
||||
solid: {
|
||||
slate:
|
||||
'bg-slate-900 text-white hover:bg-slate-700 hover:text-slate-100 active:bg-slate-800 active:text-slate-300 focus-visible:outline-slate-900',
|
||||
blue: 'bg-blue-600 text-white hover:text-slate-100 hover:bg-blue-500 active:bg-blue-800 active:text-blue-100 focus-visible:outline-blue-600',
|
||||
white:
|
||||
'bg-white text-slate-900 hover:bg-blue-50 active:bg-blue-200 active:text-slate-600 focus-visible:outline-white',
|
||||
},
|
||||
outline: {
|
||||
slate:
|
||||
'ring-slate-200 text-slate-700 hover:text-slate-900 hover:ring-slate-300 active:bg-slate-100 active:text-slate-600 focus-visible:outline-blue-600 focus-visible:ring-slate-300',
|
||||
white:
|
||||
'ring-slate-700 text-white hover:ring-slate-500 active:ring-slate-700 active:text-slate-400 focus-visible:outline-white',
|
||||
},
|
||||
}
|
||||
|
||||
type ButtonProps = (
|
||||
| {
|
||||
variant?: 'solid'
|
||||
color?: keyof typeof variantStyles.solid
|
||||
}
|
||||
| {
|
||||
variant: 'outline'
|
||||
color?: keyof typeof variantStyles.outline
|
||||
}
|
||||
) &
|
||||
(
|
||||
| Omit<React.ComponentPropsWithoutRef<typeof Link>, 'color'>
|
||||
| (Omit<React.ComponentPropsWithoutRef<'button'>, 'color'> & {
|
||||
href?: undefined
|
||||
})
|
||||
)
|
||||
|
||||
export function Button({ className, ...props }: ButtonProps) {
|
||||
props.variant ??= 'solid'
|
||||
props.color ??= 'slate'
|
||||
|
||||
className = clsx(
|
||||
baseStyles[props.variant],
|
||||
props.variant === 'outline'
|
||||
? variantStyles.outline[props.color]
|
||||
: props.variant === 'solid'
|
||||
? variantStyles.solid[props.color]
|
||||
: undefined,
|
||||
className,
|
||||
)
|
||||
|
||||
return typeof props.href === 'undefined' ? (
|
||||
<button className={className} {...props} />
|
||||
) : (
|
||||
<Link className={className} {...props} />
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
import { Button } from '@/components/Button'
|
||||
import { Container } from '@/components/Container'
|
||||
import backgroundImage from '@/images/background-call-to-action.jpg'
|
||||
|
||||
export function CallToAction() {
|
||||
return (
|
||||
<section
|
||||
id="get-started-today"
|
||||
className="relative overflow-hidden bg-blue-600 py-32"
|
||||
>
|
||||
<Image
|
||||
className="absolute left-1/2 top-1/2 max-w-none -translate-x-1/2 -translate-y-1/2"
|
||||
src={backgroundImage}
|
||||
alt=""
|
||||
width={2347}
|
||||
height={1244}
|
||||
unoptimized
|
||||
/>
|
||||
<Container className="relative">
|
||||
<div className="mx-auto max-w-lg text-center">
|
||||
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl">
|
||||
Get started today
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-white">
|
||||
It’s time to take control of your books. Buy our software so you can
|
||||
feel like you’re doing something productive.
|
||||
</p>
|
||||
<Button href="/register" color="white" className="mt-10">
|
||||
Get 6 months free
|
||||
</Button>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import clsx from 'clsx'
|
||||
|
||||
export function Container({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentPropsWithoutRef<'div'>) {
|
||||
return (
|
||||
<div
|
||||
className={clsx('mx-auto max-w-7xl px-4 sm:px-6 lg:px-8', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
import { Container } from '@/components/Container'
|
||||
import backgroundImage from '@/images/background-faqs.jpg'
|
||||
|
||||
const faqs = [
|
||||
[
|
||||
{
|
||||
question: 'Does TaxPal handle VAT?',
|
||||
answer:
|
||||
'Well no, but if you move your company offshore you can probably ignore it.',
|
||||
},
|
||||
{
|
||||
question: 'Can I pay for my subscription via purchase order?',
|
||||
answer: 'Absolutely, we are happy to take your money in all forms.',
|
||||
},
|
||||
{
|
||||
question: 'How do I apply for a job at TaxPal?',
|
||||
answer:
|
||||
'We only hire our customers, so subscribe for a minimum of 6 months and then let’s talk.',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
question: 'What was that testimonial about tax fraud all about?',
|
||||
answer:
|
||||
'TaxPal is just a software application, ultimately your books are your responsibility.',
|
||||
},
|
||||
{
|
||||
question:
|
||||
'TaxPal sounds horrible but why do I still feel compelled to purchase?',
|
||||
answer:
|
||||
'This is the power of excellent visual design. You just can’t resist it, no matter how poorly it actually functions.',
|
||||
},
|
||||
{
|
||||
question:
|
||||
'I found other companies called TaxPal, are you sure you can use this name?',
|
||||
answer:
|
||||
'Honestly not sure at all. We haven’t actually incorporated or anything, we just thought it sounded cool and made this website.',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
question: 'How do you generate reports?',
|
||||
answer:
|
||||
'You just tell us what data you need a report for, and we get our kids to create beautiful charts for you using only the finest crayons.',
|
||||
},
|
||||
{
|
||||
question: 'Can we expect more inventory features?',
|
||||
answer: 'In life it’s really better to never expect anything at all.',
|
||||
},
|
||||
{
|
||||
question: 'I lost my password, how do I get into my account?',
|
||||
answer:
|
||||
'Send us an email and we will send you a copy of our latest password spreadsheet so you can find your information.',
|
||||
},
|
||||
],
|
||||
]
|
||||
|
||||
export function Faqs() {
|
||||
return (
|
||||
<section
|
||||
id="faq"
|
||||
aria-labelledby="faq-title"
|
||||
className="relative overflow-hidden bg-slate-50 py-20 sm:py-32"
|
||||
>
|
||||
<Image
|
||||
className="absolute left-1/2 top-0 max-w-none -translate-y-1/4 translate-x-[-30%]"
|
||||
src={backgroundImage}
|
||||
alt=""
|
||||
width={1558}
|
||||
height={946}
|
||||
unoptimized
|
||||
/>
|
||||
<Container className="relative">
|
||||
<div className="mx-auto max-w-2xl lg:mx-0">
|
||||
<h2
|
||||
id="faq-title"
|
||||
className="font-display text-3xl tracking-tight text-slate-900 sm:text-4xl"
|
||||
>
|
||||
Frequently asked questions
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-slate-700">
|
||||
If you can’t find what you’re looking for, email our support team
|
||||
and if you’re lucky someone will get back to you.
|
||||
</p>
|
||||
</div>
|
||||
<ul
|
||||
role="list"
|
||||
className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-8 lg:max-w-none lg:grid-cols-3"
|
||||
>
|
||||
{faqs.map((column, columnIndex) => (
|
||||
<li key={columnIndex}>
|
||||
<ul role="list" className="flex flex-col gap-y-8">
|
||||
{column.map((faq, faqIndex) => (
|
||||
<li key={faqIndex}>
|
||||
<h3 className="font-display text-lg leading-7 text-slate-900">
|
||||
{faq.question}
|
||||
</h3>
|
||||
<p className="mt-4 text-sm text-slate-700">{faq.answer}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import { useId } from 'react'
|
||||
import clsx from 'clsx'
|
||||
|
||||
const formClasses =
|
||||
'block w-full appearance-none rounded-md border border-gray-200 bg-gray-50 px-3 py-2 text-gray-900 placeholder-gray-400 focus:border-blue-500 focus:bg-white focus:outline-none focus:ring-blue-500 sm:text-sm'
|
||||
|
||||
function Label({ id, children }: { id: string; children: React.ReactNode }) {
|
||||
return (
|
||||
<label
|
||||
htmlFor={id}
|
||||
className="mb-3 block text-sm font-medium text-gray-700"
|
||||
>
|
||||
{children}
|
||||
</label>
|
||||
)
|
||||
}
|
||||
|
||||
export function TextField({
|
||||
label,
|
||||
type = 'text',
|
||||
className,
|
||||
...props
|
||||
}: Omit<React.ComponentPropsWithoutRef<'input'>, 'id'> & { label: string }) {
|
||||
let id = useId()
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{label && <Label id={id}>{label}</Label>}
|
||||
<input id={id} type={type} {...props} className={formClasses} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function SelectField({
|
||||
label,
|
||||
className,
|
||||
...props
|
||||
}: Omit<React.ComponentPropsWithoutRef<'select'>, 'id'> & { label: string }) {
|
||||
let id = useId()
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{label && <Label id={id}>{label}</Label>}
|
||||
<select id={id} {...props} className={clsx(formClasses, 'pr-8')} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
import { Container } from '@/components/Container'
|
||||
import { Logo } from '@/components/Logo'
|
||||
import { NavLink } from '@/components/NavLink'
|
||||
|
||||
export function Footer() {
|
||||
return (
|
||||
<footer className="bg-slate-50">
|
||||
<Container>
|
||||
<div className="py-16">
|
||||
<Logo className="mx-auto h-10 w-auto" />
|
||||
<nav className="mt-10 text-sm" aria-label="quick links">
|
||||
<div className="-my-1 flex justify-center gap-x-6">
|
||||
<NavLink href="#features">Features</NavLink>
|
||||
<NavLink href="#testimonials">Testimonials</NavLink>
|
||||
<NavLink href="#pricing">Pricing</NavLink>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
<div className="flex flex-col items-center border-t border-slate-400/10 py-10 sm:flex-row-reverse sm:justify-between">
|
||||
<div className="flex gap-x-6">
|
||||
<Link href="#" className="group" aria-label="TaxPal on X">
|
||||
<svg
|
||||
className="h-6 w-6 fill-slate-500 group-hover:fill-slate-700"
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path d="M13.3174 10.7749L19.1457 4H17.7646L12.7039 9.88256L8.66193 4H4L10.1122 12.8955L4 20H5.38119L10.7254 13.7878L14.994 20H19.656L13.3171 10.7749H13.3174ZM11.4257 12.9738L10.8064 12.0881L5.87886 5.03974H8.00029L11.9769 10.728L12.5962 11.6137L17.7652 19.0075H15.6438L11.4257 12.9742V12.9738Z" />
|
||||
</svg>
|
||||
</Link>
|
||||
<Link href="#" className="group" aria-label="TaxPal on GitHub">
|
||||
<svg
|
||||
className="h-6 w-6 fill-slate-500 group-hover:fill-slate-700"
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0 1 12 6.844a9.59 9.59 0 0 1 2.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0 0 22 12.017C22 6.484 17.522 2 12 2Z" />
|
||||
</svg>
|
||||
</Link>
|
||||
</div>
|
||||
<p className="mt-6 text-sm text-slate-500 sm:mt-0">
|
||||
Copyright © {new Date().getFullYear()} TaxPal. All rights
|
||||
reserved.
|
||||
</p>
|
||||
</div>
|
||||
</Container>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
'use client'
|
||||
|
||||
import Link from 'next/link'
|
||||
import {
|
||||
Popover,
|
||||
PopoverButton,
|
||||
PopoverBackdrop,
|
||||
PopoverPanel,
|
||||
} from '@headlessui/react'
|
||||
import clsx from 'clsx'
|
||||
|
||||
import { Button } from '@/components/Button'
|
||||
import { Container } from '@/components/Container'
|
||||
import { Logo } from '@/components/Logo'
|
||||
import { NavLink } from '@/components/NavLink'
|
||||
|
||||
function MobileNavLink({
|
||||
href,
|
||||
children,
|
||||
}: {
|
||||
href: string
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<PopoverButton as={Link} href={href} className="block w-full p-2">
|
||||
{children}
|
||||
</PopoverButton>
|
||||
)
|
||||
}
|
||||
|
||||
function MobileNavIcon({ open }: { open: boolean }) {
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="h-3.5 w-3.5 overflow-visible stroke-slate-700"
|
||||
fill="none"
|
||||
strokeWidth={2}
|
||||
strokeLinecap="round"
|
||||
>
|
||||
<path
|
||||
d="M0 1H14M0 7H14M0 13H14"
|
||||
className={clsx(
|
||||
'origin-center transition',
|
||||
open && 'scale-90 opacity-0',
|
||||
)}
|
||||
/>
|
||||
<path
|
||||
d="M2 2L12 12M12 2L2 12"
|
||||
className={clsx(
|
||||
'origin-center transition',
|
||||
!open && 'scale-90 opacity-0',
|
||||
)}
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function MobileNavigation() {
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverButton
|
||||
className="relative z-10 flex h-8 w-8 items-center justify-center ui-not-focus-visible:outline-none"
|
||||
aria-label="Toggle Navigation"
|
||||
>
|
||||
{({ open }) => <MobileNavIcon open={open} />}
|
||||
</PopoverButton>
|
||||
<PopoverBackdrop
|
||||
transition
|
||||
className="fixed inset-0 bg-slate-300/50 duration-150 data-[closed]:opacity-0 data-[enter]:ease-out data-[leave]:ease-in"
|
||||
/>
|
||||
<PopoverPanel
|
||||
transition
|
||||
className="absolute inset-x-0 top-full mt-4 flex origin-top flex-col rounded-2xl bg-white p-4 text-lg tracking-tight text-slate-900 shadow-xl ring-1 ring-slate-900/5 data-[closed]:scale-95 data-[closed]:opacity-0 data-[enter]:duration-150 data-[leave]:duration-100 data-[enter]:ease-out data-[leave]:ease-in"
|
||||
>
|
||||
<MobileNavLink href="#features">Features</MobileNavLink>
|
||||
<MobileNavLink href="#testimonials">Testimonials</MobileNavLink>
|
||||
<MobileNavLink href="#pricing">Pricing</MobileNavLink>
|
||||
<hr className="m-2 border-slate-300/40" />
|
||||
<MobileNavLink href="/login">Sign in</MobileNavLink>
|
||||
</PopoverPanel>
|
||||
</Popover>
|
||||
)
|
||||
}
|
||||
|
||||
export function Header() {
|
||||
return (
|
||||
<header className="py-10">
|
||||
<Container>
|
||||
<nav className="relative z-50 flex justify-between">
|
||||
<div className="flex items-center md:gap-x-12">
|
||||
<Link href="#" aria-label="Home">
|
||||
<Logo className="h-10 w-auto" />
|
||||
</Link>
|
||||
<div className="hidden md:flex md:gap-x-6">
|
||||
<NavLink href="#features">Features</NavLink>
|
||||
<NavLink href="#testimonials">Testimonials</NavLink>
|
||||
<NavLink href="#pricing">Pricing</NavLink>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-x-5 md:gap-x-8">
|
||||
<div className="hidden md:block">
|
||||
<NavLink href="/login">Sign in</NavLink>
|
||||
</div>
|
||||
<Button href="/register" color="blue">
|
||||
<span>
|
||||
Get started <span className="hidden lg:inline">today</span>
|
||||
</span>
|
||||
</Button>
|
||||
<div className="-mr-1 md:hidden">
|
||||
<MobileNavigation />
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</Container>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
import { Button } from '@/components/Button'
|
||||
import { Container } from '@/components/Container'
|
||||
import logoLaravel from '@/images/logos/laravel.svg'
|
||||
import logoMirage from '@/images/logos/mirage.svg'
|
||||
import logoStatamic from '@/images/logos/statamic.svg'
|
||||
import logoStaticKit from '@/images/logos/statickit.svg'
|
||||
import logoTransistor from '@/images/logos/transistor.svg'
|
||||
import logoTuple from '@/images/logos/tuple.svg'
|
||||
|
||||
export function Hero() {
|
||||
return (
|
||||
<Container className="pb-16 pt-20 text-center lg:pt-32">
|
||||
<h1 className="mx-auto max-w-4xl font-display text-5xl font-medium tracking-tight text-slate-900 sm:text-7xl">
|
||||
Accounting{' '}
|
||||
<span className="relative whitespace-nowrap text-blue-600">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 418 42"
|
||||
className="absolute left-0 top-2/3 h-[0.58em] w-full fill-blue-300/70"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<path d="M203.371.916c-26.013-2.078-76.686 1.963-124.73 9.946L67.3 12.749C35.421 18.062 18.2 21.766 6.004 25.934 1.244 27.561.828 27.778.874 28.61c.07 1.214.828 1.121 9.595-1.176 9.072-2.377 17.15-3.92 39.246-7.496C123.565 7.986 157.869 4.492 195.942 5.046c7.461.108 19.25 1.696 19.17 2.582-.107 1.183-7.874 4.31-25.75 10.366-21.992 7.45-35.43 12.534-36.701 13.884-2.173 2.308-.202 4.407 4.442 4.734 2.654.187 3.263.157 15.593-.78 35.401-2.686 57.944-3.488 88.365-3.143 46.327.526 75.721 2.23 130.788 7.584 19.787 1.924 20.814 1.98 24.557 1.332l.066-.011c1.201-.203 1.53-1.825.399-2.335-2.911-1.31-4.893-1.604-22.048-3.261-57.509-5.556-87.871-7.36-132.059-7.842-23.239-.254-33.617-.116-50.627.674-11.629.54-42.371 2.494-46.696 2.967-2.359.259 8.133-3.625 26.504-9.81 23.239-7.825 27.934-10.149 28.304-14.005.417-4.348-3.529-6-16.878-7.066Z" />
|
||||
</svg>
|
||||
<span className="relative">made simple</span>
|
||||
</span>{' '}
|
||||
for small businesses.
|
||||
</h1>
|
||||
<p className="mx-auto mt-6 max-w-2xl text-lg tracking-tight text-slate-700">
|
||||
Most bookkeeping software is accurate, but hard to use. We make the
|
||||
opposite trade-off, and hope you don’t get audited.
|
||||
</p>
|
||||
<div className="mt-10 flex justify-center gap-x-6">
|
||||
<Button href="/register">Get 6 months free</Button>
|
||||
<Button
|
||||
href="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
||||
variant="outline"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="h-3 w-3 flex-none fill-blue-600 group-active:fill-current"
|
||||
>
|
||||
<path d="m9.997 6.91-7.583 3.447A1 1 0 0 1 1 9.447V2.553a1 1 0 0 1 1.414-.91L9.997 5.09c.782.355.782 1.465 0 1.82Z" />
|
||||
</svg>
|
||||
<span className="ml-3">Watch video</span>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="mt-36 lg:mt-44">
|
||||
<p className="font-display text-base text-slate-900">
|
||||
Trusted by these six companies so far
|
||||
</p>
|
||||
<ul
|
||||
role="list"
|
||||
className="mt-8 flex items-center justify-center gap-x-8 sm:flex-col sm:gap-x-0 sm:gap-y-10 xl:flex-row xl:gap-x-12 xl:gap-y-0"
|
||||
>
|
||||
{[
|
||||
[
|
||||
{ name: 'Transistor', logo: logoTransistor },
|
||||
{ name: 'Tuple', logo: logoTuple },
|
||||
{ name: 'StaticKit', logo: logoStaticKit },
|
||||
],
|
||||
[
|
||||
{ name: 'Mirage', logo: logoMirage },
|
||||
{ name: 'Laravel', logo: logoLaravel },
|
||||
{ name: 'Statamic', logo: logoStatamic },
|
||||
],
|
||||
].map((group, groupIndex) => (
|
||||
<li key={groupIndex}>
|
||||
<ul
|
||||
role="list"
|
||||
className="flex flex-col items-center gap-y-8 sm:flex-row sm:gap-x-12 sm:gap-y-0"
|
||||
>
|
||||
{group.map((company) => (
|
||||
<li key={company.name} className="flex">
|
||||
<Image src={company.logo} alt={company.name} unoptimized />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
export function Logo(props: React.ComponentPropsWithoutRef<'svg'>) {
|
||||
return (
|
||||
<svg aria-hidden="true" viewBox="0 0 109 40" {...props}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M0 20c0 11.046 8.954 20 20 20s20-8.954 20-20S31.046 0 20 0 0 8.954 0 20Zm20 16c-7.264 0-13.321-5.163-14.704-12.02C4.97 22.358 6.343 21 8 21h24c1.657 0 3.031 1.357 2.704 2.98C33.32 30.838 27.264 36 20 36Z"
|
||||
fill="#2563EB"
|
||||
/>
|
||||
<path
|
||||
d="M55.528 26.57V15.842H52V13.97h9.108v1.872h-3.636V26.57h-1.944Z"
|
||||
fill="#0F172A"
|
||||
/>
|
||||
<path
|
||||
d="M83.084 26.57v-12.6h5.346c.744 0 1.416.18 2.016.54a3.773 3.773 0 0 1 1.44 1.44c.36.612.54 1.302.54 2.07 0 .78-.18 1.482-.54 2.106a4 4 0 0 1-1.44 1.494c-.6.36-1.272.54-2.016.54h-2.646v4.41h-2.7Zm2.664-6.84h2.376c.288 0 .546-.072.774-.216.228-.156.408-.36.54-.612a1.71 1.71 0 0 0 .216-.864c0-.324-.072-.606-.216-.846a1.394 1.394 0 0 0-.54-.576 1.419 1.419 0 0 0-.774-.216h-2.376v3.33ZM106.227 26.57V13.25h2.556v13.32h-2.556Z"
|
||||
fill="#2563EB"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M95.906 26.102c.636.432 1.35.648 2.142.648.444 0 .864-.066 1.26-.198a4.25 4.25 0 0 0 1.062-.558 3.78 3.78 0 0 0 .702-.668v1.244h2.574v-9.522h-2.538v1.248a3.562 3.562 0 0 0-.648-.672 3.13 3.13 0 0 0-1.026-.558 3.615 3.615 0 0 0-1.278-.216c-.828 0-1.566.216-2.214.648-.648.42-1.164 1.002-1.548 1.746-.372.732-.558 1.578-.558 2.538 0 .96.186 1.812.558 2.556.372.744.876 1.332 1.512 1.764Zm4.104-1.908c-.36.228-.78.342-1.26.342-.468 0-.882-.114-1.242-.342a2.387 2.387 0 0 1-.828-.954c-.204-.42-.306-.906-.306-1.458 0-.54.102-1.014.306-1.422.204-.408.48-.726.828-.954.36-.24.774-.36 1.242-.36.48 0 .9.12 1.26.36.36.228.636.546.828.954.204.408.306.882.306 1.422 0 .552-.102 1.038-.306 1.458a2.218 2.218 0 0 1-.828.954Z"
|
||||
fill="#2563EB"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="m76.322 23.197 2.595 3.373h2.268l-3.662-4.787 3.338-4.663h-2.196l-2.162 3.334-2.554-3.334h-2.34l3.652 4.71-3.634 4.74h2.196l2.5-3.373ZM62.738 26.102a3.78 3.78 0 0 0 2.142.648c.456 0 .888-.072 1.296-.216.42-.144.798-.336 1.134-.576a3.418 3.418 0 0 0 .864-.835v1.447h1.872v-9.45h-1.872v1.45a3.118 3.118 0 0 0-.72-.82 3.2 3.2 0 0 0-1.062-.612 4.033 4.033 0 0 0-1.35-.216c-.828 0-1.578.21-2.25.63-.66.42-1.188 1.002-1.584 1.746-.384.732-.576 1.572-.576 2.52 0 .936.192 1.776.576 2.52.384.744.894 1.332 1.53 1.764Zm4.122-1.476c-.432.276-.93.414-1.494.414a2.682 2.682 0 0 1-1.476-.414 2.987 2.987 0 0 1-1.008-1.134c-.24-.492-.36-1.05-.36-1.674 0-.612.12-1.158.36-1.638.252-.48.588-.858 1.008-1.134a2.682 2.682 0 0 1 1.476-.414c.564 0 1.062.138 1.494.414.432.276.768.654 1.008 1.134.252.48.378 1.026.378 1.638 0 .624-.126 1.182-.378 1.674-.24.48-.576.858-1.008 1.134Z"
|
||||
fill="#0F172A"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
export function NavLink({
|
||||
href,
|
||||
children,
|
||||
}: {
|
||||
href: string
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<Link
|
||||
href={href}
|
||||
className="inline-block rounded-lg px-2 py-1 text-sm text-slate-700 hover:bg-slate-100 hover:text-slate-900"
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
import clsx from 'clsx'
|
||||
|
||||
import { Button } from '@/components/Button'
|
||||
import { Container } from '@/components/Container'
|
||||
|
||||
function SwirlyDoodle(props: React.ComponentPropsWithoutRef<'svg'>) {
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 281 40"
|
||||
preserveAspectRatio="none"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M240.172 22.994c-8.007 1.246-15.477 2.23-31.26 4.114-18.506 2.21-26.323 2.977-34.487 3.386-2.971.149-3.727.324-6.566 1.523-15.124 6.388-43.775 9.404-69.425 7.31-26.207-2.14-50.986-7.103-78-15.624C10.912 20.7.988 16.143.734 14.657c-.066-.381.043-.344 1.324.456 10.423 6.506 49.649 16.322 77.8 19.468 23.708 2.65 38.249 2.95 55.821 1.156 9.407-.962 24.451-3.773 25.101-4.692.074-.104.053-.155-.058-.135-1.062.195-13.863-.271-18.848-.687-16.681-1.389-28.722-4.345-38.142-9.364-15.294-8.15-7.298-19.232 14.802-20.514 16.095-.934 32.793 1.517 47.423 6.96 13.524 5.033 17.942 12.326 11.463 18.922l-.859.874.697-.006c2.681-.026 15.304-1.302 29.208-2.953 25.845-3.07 35.659-4.519 54.027-7.978 9.863-1.858 11.021-2.048 13.055-2.145a61.901 61.901 0 0 0 4.506-.417c1.891-.259 2.151-.267 1.543-.047-.402.145-2.33.913-4.285 1.707-4.635 1.882-5.202 2.07-8.736 2.903-3.414.805-19.773 3.797-26.404 4.829Zm40.321-9.93c.1-.066.231-.085.29-.041.059.043-.024.096-.183.119-.177.024-.219-.007-.107-.079ZM172.299 26.22c9.364-6.058 5.161-12.039-12.304-17.51-11.656-3.653-23.145-5.47-35.243-5.576-22.552-.198-33.577 7.462-21.321 14.814 12.012 7.205 32.994 10.557 61.531 9.831 4.563-.116 5.372-.288 7.337-1.559Z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function CheckIcon({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentPropsWithoutRef<'svg'>) {
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className={clsx(
|
||||
'h-6 w-6 flex-none fill-current stroke-current',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M9.307 12.248a.75.75 0 1 0-1.114 1.004l1.114-1.004ZM11 15.25l-.557.502a.75.75 0 0 0 1.15-.043L11 15.25Zm4.844-5.041a.75.75 0 0 0-1.188-.918l1.188.918Zm-7.651 3.043 2.25 2.5 1.114-1.004-2.25-2.5-1.114 1.004Zm3.4 2.457 4.25-5.5-1.187-.918-4.25 5.5 1.188.918Z"
|
||||
strokeWidth={0}
|
||||
/>
|
||||
<circle
|
||||
cx={12}
|
||||
cy={12}
|
||||
r={8.25}
|
||||
fill="none"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function Plan({
|
||||
name,
|
||||
price,
|
||||
description,
|
||||
href,
|
||||
features,
|
||||
featured = false,
|
||||
}: {
|
||||
name: string
|
||||
price: string
|
||||
description: string
|
||||
href: string
|
||||
features: Array<string>
|
||||
featured?: boolean
|
||||
}) {
|
||||
return (
|
||||
<section
|
||||
className={clsx(
|
||||
'flex flex-col rounded-3xl px-6 sm:px-8',
|
||||
featured ? 'order-first bg-blue-600 py-8 lg:order-none' : 'lg:py-8',
|
||||
)}
|
||||
>
|
||||
<h3 className="mt-5 font-display text-lg text-white">{name}</h3>
|
||||
<p
|
||||
className={clsx(
|
||||
'mt-2 text-base',
|
||||
featured ? 'text-white' : 'text-slate-400',
|
||||
)}
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
<p className="order-first font-display text-5xl font-light tracking-tight text-white">
|
||||
{price}
|
||||
</p>
|
||||
<ul
|
||||
role="list"
|
||||
className={clsx(
|
||||
'order-last mt-10 flex flex-col gap-y-3 text-sm',
|
||||
featured ? 'text-white' : 'text-slate-200',
|
||||
)}
|
||||
>
|
||||
{features.map((feature) => (
|
||||
<li key={feature} className="flex">
|
||||
<CheckIcon className={featured ? 'text-white' : 'text-slate-400'} />
|
||||
<span className="ml-4">{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Button
|
||||
href={href}
|
||||
variant={featured ? 'solid' : 'outline'}
|
||||
color="white"
|
||||
className="mt-8"
|
||||
aria-label={`Get started with the ${name} plan for ${price}`}
|
||||
>
|
||||
Get started
|
||||
</Button>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
export function Pricing() {
|
||||
return (
|
||||
<section
|
||||
id="pricing"
|
||||
aria-label="Pricing"
|
||||
className="bg-slate-900 py-20 sm:py-32"
|
||||
>
|
||||
<Container>
|
||||
<div className="md:text-center">
|
||||
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl">
|
||||
<span className="relative whitespace-nowrap">
|
||||
<SwirlyDoodle className="absolute left-0 top-1/2 h-[1em] w-full fill-blue-400" />
|
||||
<span className="relative">Simple pricing,</span>
|
||||
</span>{' '}
|
||||
for everyone.
|
||||
</h2>
|
||||
<p className="mt-4 text-lg text-slate-400">
|
||||
It doesn’t matter what size your business is, our software won’t
|
||||
work well for you.
|
||||
</p>
|
||||
</div>
|
||||
<div className="-mx-4 mt-16 grid max-w-2xl grid-cols-1 gap-y-10 sm:mx-auto lg:-mx-8 lg:max-w-none lg:grid-cols-3 xl:mx-0 xl:gap-x-8">
|
||||
<Plan
|
||||
name="Starter"
|
||||
price="$9"
|
||||
description="Good for anyone who is self-employed and just getting started."
|
||||
href="/register"
|
||||
features={[
|
||||
'Send 10 quotes and invoices',
|
||||
'Connect up to 2 bank accounts',
|
||||
'Track up to 15 expenses per month',
|
||||
'Manual payroll support',
|
||||
'Export up to 3 reports',
|
||||
]}
|
||||
/>
|
||||
<Plan
|
||||
featured
|
||||
name="Small business"
|
||||
price="$15"
|
||||
description="Perfect for small / medium sized businesses."
|
||||
href="/register"
|
||||
features={[
|
||||
'Send 25 quotes and invoices',
|
||||
'Connect up to 5 bank accounts',
|
||||
'Track up to 50 expenses per month',
|
||||
'Automated payroll support',
|
||||
'Export up to 12 reports',
|
||||
'Bulk reconcile transactions',
|
||||
'Track in multiple currencies',
|
||||
]}
|
||||
/>
|
||||
<Plan
|
||||
name="Enterprise"
|
||||
price="$39"
|
||||
description="For even the biggest enterprise companies."
|
||||
href="/register"
|
||||
features={[
|
||||
'Send unlimited quotes and invoices',
|
||||
'Connect up to 15 bank accounts',
|
||||
'Track up to 200 expenses per month',
|
||||
'Automated payroll support',
|
||||
'Export up to 25 reports, including TPS',
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import Image from 'next/image'
|
||||
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '@headlessui/react'
|
||||
import clsx from 'clsx'
|
||||
|
||||
import { Container } from '@/components/Container'
|
||||
import backgroundImage from '@/images/background-features.jpg'
|
||||
import screenshotExpenses from '@/images/screenshots/expenses.png'
|
||||
import screenshotPayroll from '@/images/screenshots/payroll.png'
|
||||
import screenshotReporting from '@/images/screenshots/reporting.png'
|
||||
import screenshotVatReturns from '@/images/screenshots/vat-returns.png'
|
||||
|
||||
const features = [
|
||||
{
|
||||
title: 'Payroll',
|
||||
description:
|
||||
"Keep track of everyone's salaries and whether or not they've been paid. Direct deposit not supported.",
|
||||
image: screenshotPayroll,
|
||||
},
|
||||
{
|
||||
title: 'Claim expenses',
|
||||
description:
|
||||
"All of your receipts organized into one place, as long as you don't mind typing in the data by hand.",
|
||||
image: screenshotExpenses,
|
||||
},
|
||||
{
|
||||
title: 'VAT handling',
|
||||
description:
|
||||
"We only sell our software to companies who don't deal with VAT at all, so technically we do all the VAT stuff they need.",
|
||||
image: screenshotVatReturns,
|
||||
},
|
||||
{
|
||||
title: 'Reporting',
|
||||
description:
|
||||
'Easily export your data into an Excel spreadsheet where you can do whatever the hell you want with it.',
|
||||
image: screenshotReporting,
|
||||
},
|
||||
]
|
||||
|
||||
export function PrimaryFeatures() {
|
||||
let [tabOrientation, setTabOrientation] = useState<'horizontal' | 'vertical'>(
|
||||
'horizontal',
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
let lgMediaQuery = window.matchMedia('(min-width: 1024px)')
|
||||
|
||||
function onMediaQueryChange({ matches }: { matches: boolean }) {
|
||||
setTabOrientation(matches ? 'vertical' : 'horizontal')
|
||||
}
|
||||
|
||||
onMediaQueryChange(lgMediaQuery)
|
||||
lgMediaQuery.addEventListener('change', onMediaQueryChange)
|
||||
|
||||
return () => {
|
||||
lgMediaQuery.removeEventListener('change', onMediaQueryChange)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<section
|
||||
id="features"
|
||||
aria-label="Features for running your books"
|
||||
className="relative overflow-hidden bg-blue-600 pb-28 pt-20 sm:py-32"
|
||||
>
|
||||
<Image
|
||||
className="absolute left-1/2 top-1/2 max-w-none translate-x-[-44%] translate-y-[-42%]"
|
||||
src={backgroundImage}
|
||||
alt=""
|
||||
width={2245}
|
||||
height={1636}
|
||||
unoptimized
|
||||
/>
|
||||
<Container className="relative">
|
||||
<div className="max-w-2xl md:mx-auto md:text-center xl:max-w-none">
|
||||
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl md:text-5xl">
|
||||
Everything you need to run your books.
|
||||
</h2>
|
||||
<p className="mt-6 text-lg tracking-tight text-blue-100">
|
||||
Well everything you need if you aren’t that picky about minor
|
||||
details like tax compliance.
|
||||
</p>
|
||||
</div>
|
||||
<TabGroup
|
||||
className="mt-16 grid grid-cols-1 items-center gap-y-2 pt-10 sm:gap-y-6 md:mt-20 lg:grid-cols-12 lg:pt-0"
|
||||
vertical={tabOrientation === 'vertical'}
|
||||
>
|
||||
{({ selectedIndex }) => (
|
||||
<>
|
||||
<div className="-mx-4 flex overflow-x-auto pb-4 sm:mx-0 sm:overflow-visible sm:pb-0 lg:col-span-5">
|
||||
<TabList className="relative z-10 flex gap-x-4 whitespace-nowrap px-4 sm:mx-auto sm:px-0 lg:mx-0 lg:block lg:gap-x-0 lg:gap-y-1 lg:whitespace-normal">
|
||||
{features.map((feature, featureIndex) => (
|
||||
<div
|
||||
key={feature.title}
|
||||
className={clsx(
|
||||
'group relative rounded-full px-4 py-1 lg:rounded-l-xl lg:rounded-r-none lg:p-6',
|
||||
selectedIndex === featureIndex
|
||||
? 'bg-white lg:bg-white/10 lg:ring-1 lg:ring-inset lg:ring-white/10'
|
||||
: 'hover:bg-white/10 lg:hover:bg-white/5',
|
||||
)}
|
||||
>
|
||||
<h3>
|
||||
<Tab
|
||||
className={clsx(
|
||||
'font-display text-lg ui-not-focus-visible:outline-none',
|
||||
selectedIndex === featureIndex
|
||||
? 'text-blue-600 lg:text-white'
|
||||
: 'text-blue-100 hover:text-white lg:text-white',
|
||||
)}
|
||||
>
|
||||
<span className="absolute inset-0 rounded-full lg:rounded-l-xl lg:rounded-r-none" />
|
||||
{feature.title}
|
||||
</Tab>
|
||||
</h3>
|
||||
<p
|
||||
className={clsx(
|
||||
'mt-2 hidden text-sm lg:block',
|
||||
selectedIndex === featureIndex
|
||||
? 'text-white'
|
||||
: 'text-blue-100 group-hover:text-white',
|
||||
)}
|
||||
>
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</TabList>
|
||||
</div>
|
||||
<TabPanels className="lg:col-span-7">
|
||||
{features.map((feature) => (
|
||||
<TabPanel key={feature.title} unmount={false}>
|
||||
<div className="relative sm:px-6 lg:hidden">
|
||||
<div className="absolute -inset-x-4 bottom-[-4.25rem] top-[-6.5rem] bg-white/10 ring-1 ring-inset ring-white/10 sm:inset-x-0 sm:rounded-t-xl" />
|
||||
<p className="relative mx-auto max-w-2xl text-base text-white sm:text-center">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-10 w-[45rem] overflow-hidden rounded-xl bg-slate-50 shadow-xl shadow-blue-900/20 sm:w-auto lg:mt-0 lg:w-[67.8125rem]">
|
||||
<Image
|
||||
className="w-full"
|
||||
src={feature.image}
|
||||
alt=""
|
||||
priority
|
||||
sizes="(min-width: 1024px) 67.8125rem, (min-width: 640px) 100vw, 45rem"
|
||||
/>
|
||||
</div>
|
||||
</TabPanel>
|
||||
))}
|
||||
</TabPanels>
|
||||
</>
|
||||
)}
|
||||
</TabGroup>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
'use client'
|
||||
|
||||
import { useId } from 'react'
|
||||
import Image, { type ImageProps } from 'next/image'
|
||||
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '@headlessui/react'
|
||||
import clsx from 'clsx'
|
||||
|
||||
import { Container } from '@/components/Container'
|
||||
import screenshotContacts from '@/images/screenshots/contacts.png'
|
||||
import screenshotInventory from '@/images/screenshots/inventory.png'
|
||||
import screenshotProfitLoss from '@/images/screenshots/profit-loss.png'
|
||||
|
||||
interface Feature {
|
||||
name: React.ReactNode
|
||||
summary: string
|
||||
description: string
|
||||
image: ImageProps['src']
|
||||
icon: React.ComponentType
|
||||
}
|
||||
|
||||
const features: Array<Feature> = [
|
||||
{
|
||||
name: 'Reporting',
|
||||
summary: 'Stay on top of things with always up-to-date reporting features.',
|
||||
description:
|
||||
'We talked about reporting in the section above but we needed three items here, so mentioning it one more time for posterity.',
|
||||
image: screenshotProfitLoss,
|
||||
icon: function ReportingIcon() {
|
||||
let id = useId()
|
||||
return (
|
||||
<>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id={id}
|
||||
x1="11.5"
|
||||
y1={18}
|
||||
x2={36}
|
||||
y2="15.5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset=".194" stopColor="#fff" />
|
||||
<stop offset={1} stopColor="#6692F1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path
|
||||
d="m30 15-4 5-4-11-4 18-4-11-4 7-4-5"
|
||||
stroke={`url(#${id})`}
|
||||
strokeWidth={2}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Inventory',
|
||||
summary:
|
||||
'Never lose track of what’s in stock with accurate inventory tracking.',
|
||||
description:
|
||||
'We don’t offer this as part of our software but that statement is inarguably true. Accurate inventory tracking would help you for sure.',
|
||||
image: screenshotInventory,
|
||||
icon: function InventoryIcon() {
|
||||
return (
|
||||
<>
|
||||
<path
|
||||
opacity=".5"
|
||||
d="M8 17a1 1 0 0 1 1-1h18a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1v-2Z"
|
||||
fill="#fff"
|
||||
/>
|
||||
<path
|
||||
opacity=".3"
|
||||
d="M8 24a1 1 0 0 1 1-1h18a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1v-2Z"
|
||||
fill="#fff"
|
||||
/>
|
||||
<path
|
||||
d="M8 10a1 1 0 0 1 1-1h18a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1v-2Z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Contacts',
|
||||
summary:
|
||||
'Organize all of your contacts, service providers, and invoices in one place.',
|
||||
description:
|
||||
'This also isn’t actually a feature, it’s just some friendly advice. We definitely recommend that you do this, you’ll feel really organized and professional.',
|
||||
image: screenshotContacts,
|
||||
icon: function ContactsIcon() {
|
||||
return (
|
||||
<>
|
||||
<path
|
||||
opacity=".5"
|
||||
d="M25.778 25.778c.39.39 1.027.393 1.384-.028A11.952 11.952 0 0 0 30 18c0-6.627-5.373-12-12-12S6 11.373 6 18c0 2.954 1.067 5.659 2.838 7.75.357.421.993.419 1.384.028.39-.39.386-1.02.036-1.448A9.959 9.959 0 0 1 8 18c0-5.523 4.477-10 10-10s10 4.477 10 10a9.959 9.959 0 0 1-2.258 6.33c-.35.427-.354 1.058.036 1.448Z"
|
||||
fill="#fff"
|
||||
/>
|
||||
<path
|
||||
d="M12 28.395V28a6 6 0 0 1 12 0v.395A11.945 11.945 0 0 1 18 30c-2.186 0-4.235-.584-6-1.605ZM21 16.5c0-1.933-.5-3.5-3-3.5s-3 1.567-3 3.5 1.343 3.5 3 3.5 3-1.567 3-3.5Z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</>
|
||||
)
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
function Feature({
|
||||
feature,
|
||||
isActive,
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentPropsWithoutRef<'div'> & {
|
||||
feature: Feature
|
||||
isActive: boolean
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(className, !isActive && 'opacity-75 hover:opacity-100')}
|
||||
{...props}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
'w-9 rounded-lg',
|
||||
isActive ? 'bg-blue-600' : 'bg-slate-500',
|
||||
)}
|
||||
>
|
||||
<svg aria-hidden="true" className="h-9 w-9" fill="none">
|
||||
<feature.icon />
|
||||
</svg>
|
||||
</div>
|
||||
<h3
|
||||
className={clsx(
|
||||
'mt-6 text-sm font-medium',
|
||||
isActive ? 'text-blue-600' : 'text-slate-600',
|
||||
)}
|
||||
>
|
||||
{feature.name}
|
||||
</h3>
|
||||
<p className="mt-2 font-display text-xl text-slate-900">
|
||||
{feature.summary}
|
||||
</p>
|
||||
<p className="mt-4 text-sm text-slate-600">{feature.description}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function FeaturesMobile() {
|
||||
return (
|
||||
<div className="-mx-4 mt-20 flex flex-col gap-y-10 overflow-hidden px-4 sm:-mx-6 sm:px-6 lg:hidden">
|
||||
{features.map((feature) => (
|
||||
<div key={feature.summary}>
|
||||
<Feature feature={feature} className="mx-auto max-w-2xl" isActive />
|
||||
<div className="relative mt-10 pb-10">
|
||||
<div className="absolute -inset-x-4 bottom-0 top-8 bg-slate-200 sm:-inset-x-6" />
|
||||
<div className="relative mx-auto w-[52.75rem] overflow-hidden rounded-xl bg-white shadow-lg shadow-slate-900/5 ring-1 ring-slate-500/10">
|
||||
<Image
|
||||
className="w-full"
|
||||
src={feature.image}
|
||||
alt=""
|
||||
sizes="52.75rem"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function FeaturesDesktop() {
|
||||
return (
|
||||
<TabGroup className="hidden lg:mt-20 lg:block">
|
||||
{({ selectedIndex }) => (
|
||||
<>
|
||||
<TabList className="grid grid-cols-3 gap-x-8">
|
||||
{features.map((feature, featureIndex) => (
|
||||
<Feature
|
||||
key={feature.summary}
|
||||
feature={{
|
||||
...feature,
|
||||
name: (
|
||||
<Tab className="ui-not-focus-visible:outline-none">
|
||||
<span className="absolute inset-0" />
|
||||
{feature.name}
|
||||
</Tab>
|
||||
),
|
||||
}}
|
||||
isActive={featureIndex === selectedIndex}
|
||||
className="relative"
|
||||
/>
|
||||
))}
|
||||
</TabList>
|
||||
<TabPanels className="relative mt-20 overflow-hidden rounded-4xl bg-slate-200 px-14 py-16 xl:px-16">
|
||||
<div className="-mx-5 flex">
|
||||
{features.map((feature, featureIndex) => (
|
||||
<TabPanel
|
||||
static
|
||||
key={feature.summary}
|
||||
className={clsx(
|
||||
'px-5 transition duration-500 ease-in-out ui-not-focus-visible:outline-none',
|
||||
featureIndex !== selectedIndex && 'opacity-60',
|
||||
)}
|
||||
style={{ transform: `translateX(-${selectedIndex * 100}%)` }}
|
||||
aria-hidden={featureIndex !== selectedIndex}
|
||||
>
|
||||
<div className="w-[52.75rem] overflow-hidden rounded-xl bg-white shadow-lg shadow-slate-900/5 ring-1 ring-slate-500/10">
|
||||
<Image
|
||||
className="w-full"
|
||||
src={feature.image}
|
||||
alt=""
|
||||
sizes="52.75rem"
|
||||
/>
|
||||
</div>
|
||||
</TabPanel>
|
||||
))}
|
||||
</div>
|
||||
<div className="pointer-events-none absolute inset-0 rounded-4xl ring-1 ring-inset ring-slate-900/10" />
|
||||
</TabPanels>
|
||||
</>
|
||||
)}
|
||||
</TabGroup>
|
||||
)
|
||||
}
|
||||
|
||||
export function SecondaryFeatures() {
|
||||
return (
|
||||
<section
|
||||
id="secondary-features"
|
||||
aria-label="Features for simplifying everyday business tasks"
|
||||
className="pb-14 pt-20 sm:pb-20 sm:pt-32 lg:pb-32"
|
||||
>
|
||||
<Container>
|
||||
<div className="mx-auto max-w-2xl md:text-center">
|
||||
<h2 className="font-display text-3xl tracking-tight text-slate-900 sm:text-4xl">
|
||||
Simplify everyday business tasks.
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-slate-700">
|
||||
Because you’d probably be a little confused if we suggested you
|
||||
complicate your everyday business tasks instead.
|
||||
</p>
|
||||
</div>
|
||||
<FeaturesMobile />
|
||||
<FeaturesDesktop />
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
import backgroundImage from '@/images/background-auth.jpg'
|
||||
|
||||
export function SlimLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<div className="relative flex min-h-full shrink-0 justify-center md:px-12 lg:px-0">
|
||||
<div className="relative z-10 flex flex-1 flex-col bg-white px-4 py-10 shadow-2xl sm:justify-center md:flex-none md:px-28">
|
||||
<main className="mx-auto w-full max-w-md sm:px-4 md:w-96 md:max-w-sm md:px-0">
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
<div className="hidden sm:contents lg:relative lg:block lg:flex-1">
|
||||
<Image
|
||||
className="absolute inset-0 h-full w-full object-cover"
|
||||
src={backgroundImage}
|
||||
alt=""
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
import { Container } from '@/components/Container'
|
||||
import avatarImage1 from '@/images/avatars/avatar-1.png'
|
||||
import avatarImage2 from '@/images/avatars/avatar-2.png'
|
||||
import avatarImage3 from '@/images/avatars/avatar-3.png'
|
||||
import avatarImage4 from '@/images/avatars/avatar-4.png'
|
||||
import avatarImage5 from '@/images/avatars/avatar-5.png'
|
||||
|
||||
const testimonials = [
|
||||
[
|
||||
{
|
||||
content:
|
||||
'TaxPal is so easy to use I can’t help but wonder if it’s really doing the things the government expects me to do.',
|
||||
author: {
|
||||
name: 'Sheryl Berge',
|
||||
role: 'CEO at Lynch LLC',
|
||||
image: avatarImage1,
|
||||
},
|
||||
},
|
||||
{
|
||||
content:
|
||||
'I’m trying to get a hold of someone in support, I’m in a lot of trouble right now and they are saying it has something to do with my books. Please get back to me right away.',
|
||||
author: {
|
||||
name: 'Amy Hahn',
|
||||
role: 'Director at Velocity Industries',
|
||||
image: avatarImage4,
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
content:
|
||||
'The best part about TaxPal is every time I pay my employees, my bank balance doesn’t go down like it used to. Looking forward to spending this extra cash when I figure out why my card is being declined.',
|
||||
author: {
|
||||
name: 'Leland Kiehn',
|
||||
role: 'Founder of Kiehn and Sons',
|
||||
image: avatarImage5,
|
||||
},
|
||||
},
|
||||
{
|
||||
content:
|
||||
'There are so many things I had to do with my old software that I just don’t do at all with TaxPal. Suspicious but I can’t say I don’t love it.',
|
||||
author: {
|
||||
name: 'Erin Powlowski',
|
||||
role: 'COO at Armstrong Inc',
|
||||
image: avatarImage2,
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
content:
|
||||
'I used to have to remit tax to the EU and with TaxPal I somehow don’t have to do that anymore. Nervous to travel there now though.',
|
||||
author: {
|
||||
name: 'Peter Renolds',
|
||||
role: 'Founder of West Inc',
|
||||
image: avatarImage3,
|
||||
},
|
||||
},
|
||||
{
|
||||
content:
|
||||
'This is the fourth email I’ve sent to your support team. I am literally being held in jail for tax fraud. Please answer your damn emails, this is important.',
|
||||
author: {
|
||||
name: 'Amy Hahn',
|
||||
role: 'Director at Velocity Industries',
|
||||
image: avatarImage4,
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
|
||||
function QuoteIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
|
||||
return (
|
||||
<svg aria-hidden="true" width={105} height={78} {...props}>
|
||||
<path d="M25.086 77.292c-4.821 0-9.115-1.205-12.882-3.616-3.767-2.561-6.78-6.102-9.04-10.622C1.054 58.534 0 53.411 0 47.686c0-5.273.904-10.396 2.712-15.368 1.959-4.972 4.746-9.567 8.362-13.786a59.042 59.042 0 0 1 12.43-11.3C28.325 3.917 33.599 1.507 39.324 0l11.074 13.786c-6.479 2.561-11.677 5.951-15.594 10.17-3.767 4.219-5.65 7.835-5.65 10.848 0 1.356.377 2.863 1.13 4.52.904 1.507 2.637 3.089 5.198 4.746 3.767 2.41 6.328 4.972 7.684 7.684 1.507 2.561 2.26 5.5 2.26 8.814 0 5.123-1.959 9.19-5.876 12.204-3.767 3.013-8.588 4.52-14.464 4.52Zm54.24 0c-4.821 0-9.115-1.205-12.882-3.616-3.767-2.561-6.78-6.102-9.04-10.622-2.11-4.52-3.164-9.643-3.164-15.368 0-5.273.904-10.396 2.712-15.368 1.959-4.972 4.746-9.567 8.362-13.786a59.042 59.042 0 0 1 12.43-11.3C82.565 3.917 87.839 1.507 93.564 0l11.074 13.786c-6.479 2.561-11.677 5.951-15.594 10.17-3.767 4.219-5.65 7.835-5.65 10.848 0 1.356.377 2.863 1.13 4.52.904 1.507 2.637 3.089 5.198 4.746 3.767 2.41 6.328 4.972 7.684 7.684 1.507 2.561 2.26 5.5 2.26 8.814 0 5.123-1.959 9.19-5.876 12.204-3.767 3.013-8.588 4.52-14.464 4.52Z" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function Testimonials() {
|
||||
return (
|
||||
<section
|
||||
id="testimonials"
|
||||
aria-label="What our customers are saying"
|
||||
className="bg-slate-50 py-20 sm:py-32"
|
||||
>
|
||||
<Container>
|
||||
<div className="mx-auto max-w-2xl md:text-center">
|
||||
<h2 className="font-display text-3xl tracking-tight text-slate-900 sm:text-4xl">
|
||||
Loved by businesses worldwide.
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-slate-700">
|
||||
Our software is so simple that people can’t help but fall in love
|
||||
with it. Simplicity is easy when you just skip tons of
|
||||
mission-critical features.
|
||||
</p>
|
||||
</div>
|
||||
<ul
|
||||
role="list"
|
||||
className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-6 sm:gap-8 lg:mt-20 lg:max-w-none lg:grid-cols-3"
|
||||
>
|
||||
{testimonials.map((column, columnIndex) => (
|
||||
<li key={columnIndex}>
|
||||
<ul role="list" className="flex flex-col gap-y-6 sm:gap-y-8">
|
||||
{column.map((testimonial, testimonialIndex) => (
|
||||
<li key={testimonialIndex}>
|
||||
<figure className="relative rounded-2xl bg-white p-6 shadow-xl shadow-slate-900/10">
|
||||
<QuoteIcon className="absolute left-6 top-6 fill-slate-100" />
|
||||
<blockquote className="relative">
|
||||
<p className="text-lg tracking-tight text-slate-900">
|
||||
{testimonial.content}
|
||||
</p>
|
||||
</blockquote>
|
||||
<figcaption className="relative mt-6 flex items-center justify-between border-t border-slate-100 pt-6">
|
||||
<div>
|
||||
<div className="font-display text-base text-slate-900">
|
||||
{testimonial.author.name}
|
||||
</div>
|
||||
<div className="mt-1 text-sm text-slate-500">
|
||||
{testimonial.author.role}
|
||||
</div>
|
||||
</div>
|
||||
<div className="overflow-hidden rounded-full bg-slate-50">
|
||||
<Image
|
||||
className="h-14 w-14 object-cover"
|
||||
src={testimonial.author.image}
|
||||
alt=""
|
||||
width={56}
|
||||
height={56}
|
||||
/>
|
||||
</div>
|
||||
</figcaption>
|
||||
</figure>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import { StatsSection } from '@/components/partner/StatsSection'
|
||||
|
||||
const stats = [
|
||||
{ value: '100–250 €', label: 'Einmalige Installationsvergütung pro Objekt' },
|
||||
{ value: '10–15 %', label: 'Laufende monatliche Provision am Kundenumsatz' },
|
||||
]
|
||||
|
||||
function InfoIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" className={className}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm.75-11.25a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0ZM9.25 9a.75.75 0 0 0 0 1.5h.25v2.25a.75.75 0 0 0 0 1.5h1.5a.75.75 0 0 0 0-1.5h-.25V9.75A.75.75 0 0 0 10 9H9.25Z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function Earnings() {
|
||||
return (
|
||||
<section
|
||||
id="einnahmemodell"
|
||||
aria-labelledby="earnings-title"
|
||||
className="py-20 sm:py-32"
|
||||
>
|
||||
<StatsSection
|
||||
eyebrow="Einnahmemodell"
|
||||
title="So verdienen Sie als Partner mit"
|
||||
titleId="earnings-title"
|
||||
stats={stats}
|
||||
>
|
||||
<p className="text-xl/8 text-slate-700">
|
||||
Sie installieren beim Kunden – GebOS rechnet monatlich mit dem
|
||||
Vermieter ab und beteiligt Sie am laufenden Umsatz.
|
||||
</p>
|
||||
<p className="mt-8 max-w-xl text-base/7 text-slate-600">
|
||||
Beispiel: Ein Vermieter mit{' '}
|
||||
<span className="font-semibold text-slate-900">20 Wohneinheiten</span>{' '}
|
||||
nutzt das GebOS UVI-Servicepaket. GebOS rechnet monatlich mit dem
|
||||
Vermieter ab. Der Installateur erhält für die Installation eine
|
||||
einmalige Vergütung und zusätzlich eine laufende Beteiligung am
|
||||
Kundenumsatz.
|
||||
</p>
|
||||
<div className="mt-8 flex items-start gap-x-3">
|
||||
<InfoIcon className="mt-0.5 h-5 w-5 flex-none fill-slate-400" />
|
||||
<p className="text-sm tracking-tight text-slate-500">
|
||||
Beispielhafte Werte. Die genaue Vergütung hängt von Objektgröße,
|
||||
Leistungsumfang und Partnerstufe ab.
|
||||
</p>
|
||||
</div>
|
||||
</StatsSection>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
import { Button } from '@/components/Button'
|
||||
import { Container } from '@/components/Container'
|
||||
import { SelectField, TextField } from '@/components/Fields'
|
||||
import backgroundImage from '@/images/background-call-to-action.jpg'
|
||||
|
||||
export function FinalCta() {
|
||||
return (
|
||||
<section
|
||||
id="partner-werden"
|
||||
className="relative overflow-hidden bg-blue-600 py-20 sm:py-28"
|
||||
>
|
||||
<Image
|
||||
className="absolute left-1/2 top-1/2 max-w-none -translate-x-1/2 -translate-y-1/2"
|
||||
src={backgroundImage}
|
||||
alt=""
|
||||
width={2347}
|
||||
height={1244}
|
||||
unoptimized
|
||||
/>
|
||||
<Container className="relative">
|
||||
<div className="mx-auto max-w-2xl text-center">
|
||||
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl">
|
||||
Werden Sie GebOS Partner und bieten Sie Ihren Kunden eine fertige
|
||||
UVI-Lösung an.
|
||||
</h2>
|
||||
<div className="mt-10 flex flex-col items-center justify-center gap-y-4 sm:flex-row sm:gap-x-6 sm:gap-y-0">
|
||||
<Button href="#beratung" color="white">
|
||||
Partnergespräch buchen
|
||||
</Button>
|
||||
<Button href="#beratung" variant="outline" color="white">
|
||||
Infopaket anfordern
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="beratung"
|
||||
className="mx-auto mt-16 max-w-2xl scroll-mt-24 rounded-3xl bg-white p-8 shadow-xl shadow-blue-900/20 sm:p-10"
|
||||
>
|
||||
<h3 className="font-display text-xl font-medium text-slate-900">
|
||||
Senden Sie uns Ihre Eckdaten
|
||||
</h3>
|
||||
<p className="mt-2 text-sm text-slate-600">
|
||||
Wir melden uns für ein unverbindliches Partnergespräch bei Ihnen.
|
||||
</p>
|
||||
<form
|
||||
action="#"
|
||||
className="mt-8 grid grid-cols-1 items-end gap-x-6 gap-y-6 sm:grid-cols-2"
|
||||
>
|
||||
<TextField
|
||||
label="Name"
|
||||
name="name"
|
||||
type="text"
|
||||
autoComplete="name"
|
||||
required
|
||||
/>
|
||||
<TextField
|
||||
label="Betrieb"
|
||||
name="company"
|
||||
type="text"
|
||||
autoComplete="organization"
|
||||
/>
|
||||
<TextField
|
||||
label="Ort / Region"
|
||||
name="region"
|
||||
type="text"
|
||||
autoComplete="address-level2"
|
||||
/>
|
||||
<TextField
|
||||
label="Anzahl Vermieter-/Hausverwaltungskunden"
|
||||
name="customer_count"
|
||||
type="text"
|
||||
/>
|
||||
<SelectField label="Gewerk" name="trade" defaultValue="">
|
||||
<option value="" disabled>
|
||||
Bitte wählen
|
||||
</option>
|
||||
<option>Elektro</option>
|
||||
<option>Sanitär</option>
|
||||
<option>SHK</option>
|
||||
<option>Sonstiges</option>
|
||||
</SelectField>
|
||||
<SelectField label="Interesse an" name="interest" defaultValue="">
|
||||
<option value="" disabled>
|
||||
Bitte wählen
|
||||
</option>
|
||||
<option>Installation</option>
|
||||
<option>Vertrieb</option>
|
||||
<option>Beidem</option>
|
||||
</SelectField>
|
||||
<div className="col-span-full">
|
||||
<Button
|
||||
type="submit"
|
||||
variant="solid"
|
||||
color="blue"
|
||||
className="w-full"
|
||||
>
|
||||
<span>
|
||||
Anfrage senden <span aria-hidden="true">→</span>
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
import { Container } from '@/components/Container'
|
||||
import { Logo } from '@/components/partner/Logo'
|
||||
|
||||
const navigation = [
|
||||
{ label: 'Was ist UVI?', href: '#was-ist-uvi' },
|
||||
{ label: 'So funktioniert es', href: '#so-funktioniert-es' },
|
||||
{ label: 'Aufgabenteilung', href: '#aufgabenteilung' },
|
||||
{ label: 'Einnahmemodell', href: '#einnahmemodell' },
|
||||
{ label: 'Partner werden', href: '#partner-werden' },
|
||||
]
|
||||
|
||||
const legal = [
|
||||
{ label: 'Impressum', href: '#' },
|
||||
{ label: 'Datenschutz', href: '#' },
|
||||
{ label: 'AGB', href: '#' },
|
||||
]
|
||||
|
||||
export function Footer() {
|
||||
return (
|
||||
<footer className="bg-slate-50">
|
||||
<Container>
|
||||
<div className="grid grid-cols-1 gap-10 py-16 md:grid-cols-2 lg:grid-cols-4">
|
||||
<div className="max-w-sm lg:col-span-2">
|
||||
<Logo className="h-10 w-auto" />
|
||||
<p className="mt-4 text-sm leading-6 text-slate-600">
|
||||
GebOS stellt die digitale Infrastruktur für UVI- und
|
||||
Verbrauchserfassungsservices bereit – damit Elektro- und
|
||||
Sanitärbetriebe Ansprechpartner vor Ort bleiben.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="font-display text-sm font-semibold text-slate-900">
|
||||
Navigation
|
||||
</h3>
|
||||
<ul role="list" className="mt-4 space-y-3 text-sm">
|
||||
{navigation.map((item) => (
|
||||
<li key={item.label}>
|
||||
<Link
|
||||
href={item.href}
|
||||
className="text-slate-600 transition hover:text-slate-900"
|
||||
>
|
||||
{item.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="font-display text-sm font-semibold text-slate-900">
|
||||
Kontakt
|
||||
</h3>
|
||||
<address className="mt-4 space-y-3 text-sm not-italic leading-6 text-slate-600">
|
||||
<p>
|
||||
GebOS GmbH
|
||||
<br />
|
||||
Musterstraße 12
|
||||
<br />
|
||||
12345 Musterstadt
|
||||
<br />
|
||||
Deutschland
|
||||
</p>
|
||||
<p className="space-y-1">
|
||||
<a
|
||||
href="tel:+49301234567"
|
||||
className="block transition hover:text-slate-900"
|
||||
>
|
||||
+49 (0)30 123 456 7
|
||||
</a>
|
||||
<a
|
||||
href="mailto:partner@gebos.example"
|
||||
className="block transition hover:text-slate-900"
|
||||
>
|
||||
partner@gebos.example
|
||||
</a>
|
||||
</p>
|
||||
</address>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-y-4 border-t border-slate-400/10 py-8 sm:flex-row-reverse sm:justify-between sm:gap-y-0">
|
||||
<div className="flex gap-x-6 text-sm">
|
||||
{legal.map((item) => (
|
||||
<Link
|
||||
key={item.label}
|
||||
href={item.href}
|
||||
className="text-slate-500 transition hover:text-slate-700"
|
||||
>
|
||||
{item.label}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<p className="text-sm text-slate-500">
|
||||
Copyright © {new Date().getFullYear()} GebOS GmbH. Alle Rechte
|
||||
vorbehalten.
|
||||
</p>
|
||||
</div>
|
||||
</Container>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import { type ReactNode } from 'react'
|
||||
import Link from 'next/link'
|
||||
|
||||
import { Container } from '@/components/Container'
|
||||
|
||||
export function GradientCallout({
|
||||
eyebrow,
|
||||
title,
|
||||
titleId,
|
||||
cta,
|
||||
children,
|
||||
}: {
|
||||
eyebrow?: string
|
||||
title: string
|
||||
titleId?: string
|
||||
cta?: { href: string; label: string }
|
||||
children?: ReactNode
|
||||
}) {
|
||||
return (
|
||||
<Container>
|
||||
<div className="relative isolate overflow-hidden bg-slate-900 px-6 py-10 text-center shadow-2xl sm:rounded-3xl sm:px-12 sm:py-12">
|
||||
{eyebrow ? (
|
||||
<p className="mb-3 text-sm font-semibold uppercase tracking-wide text-blue-400">
|
||||
{eyebrow}
|
||||
</p>
|
||||
) : null}
|
||||
<h2
|
||||
id={titleId}
|
||||
className="text-balance font-display text-2xl tracking-tight text-white sm:text-3xl"
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
{children ? (
|
||||
<div className="mx-auto mt-4 max-w-2xl text-pretty text-base/7 text-slate-300">
|
||||
{children}
|
||||
</div>
|
||||
) : null}
|
||||
{cta ? (
|
||||
<div className="mt-6">
|
||||
<Link
|
||||
href={cta.href}
|
||||
className="text-sm font-semibold text-white hover:text-blue-300"
|
||||
>
|
||||
{cta.label} <span aria-hidden="true">→</span>
|
||||
</Link>
|
||||
</div>
|
||||
) : null}
|
||||
<svg
|
||||
viewBox="0 0 1024 1024"
|
||||
aria-hidden="true"
|
||||
className="absolute left-1/2 top-1/2 -z-10 h-[64rem] w-[64rem] -translate-x-1/2 -translate-y-1/2 [mask-image:radial-gradient(closest-side,white,transparent)]"
|
||||
>
|
||||
<circle
|
||||
r={512}
|
||||
cx={512}
|
||||
cy={512}
|
||||
fill="url(#gradient-callout)"
|
||||
fillOpacity="0.7"
|
||||
/>
|
||||
<defs>
|
||||
<radialGradient id="gradient-callout">
|
||||
<stop stopColor="#3b82f6" />
|
||||
<stop offset={1} stopColor="#06b6d4" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
'use client'
|
||||
|
||||
import Link from 'next/link'
|
||||
import {
|
||||
Popover,
|
||||
PopoverButton,
|
||||
PopoverBackdrop,
|
||||
PopoverPanel,
|
||||
} from '@headlessui/react'
|
||||
import clsx from 'clsx'
|
||||
|
||||
import { Button } from '@/components/Button'
|
||||
import { Container } from '@/components/Container'
|
||||
import { NavLink } from '@/components/NavLink'
|
||||
import { Logo } from '@/components/partner/Logo'
|
||||
|
||||
function MobileNavLink({
|
||||
href,
|
||||
children,
|
||||
}: {
|
||||
href: string
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<PopoverButton as={Link} href={href} className="block w-full p-2">
|
||||
{children}
|
||||
</PopoverButton>
|
||||
)
|
||||
}
|
||||
|
||||
function MobileNavIcon({ open }: { open: boolean }) {
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="h-3.5 w-3.5 overflow-visible stroke-slate-700"
|
||||
fill="none"
|
||||
strokeWidth={2}
|
||||
strokeLinecap="round"
|
||||
>
|
||||
<path
|
||||
d="M0 1H14M0 7H14M0 13H14"
|
||||
className={clsx(
|
||||
'origin-center transition',
|
||||
open && 'scale-90 opacity-0',
|
||||
)}
|
||||
/>
|
||||
<path
|
||||
d="M2 2L12 12M12 2L2 12"
|
||||
className={clsx(
|
||||
'origin-center transition',
|
||||
!open && 'scale-90 opacity-0',
|
||||
)}
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function MobileNavigation() {
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverButton
|
||||
className="relative z-10 flex h-8 w-8 items-center justify-center ui-not-focus-visible:outline-none"
|
||||
aria-label="Toggle Navigation"
|
||||
>
|
||||
{({ open }) => <MobileNavIcon open={open} />}
|
||||
</PopoverButton>
|
||||
<PopoverBackdrop
|
||||
transition
|
||||
className="fixed inset-0 bg-slate-300/50 duration-150 data-[closed]:opacity-0 data-[enter]:ease-out data-[leave]:ease-in"
|
||||
/>
|
||||
<PopoverPanel
|
||||
transition
|
||||
className="absolute inset-x-0 top-full mt-4 flex origin-top flex-col rounded-2xl bg-white p-4 text-lg tracking-tight text-slate-900 shadow-xl ring-1 ring-slate-900/5 data-[closed]:scale-95 data-[closed]:opacity-0 data-[enter]:duration-150 data-[leave]:duration-100 data-[enter]:ease-out data-[leave]:ease-in"
|
||||
>
|
||||
<MobileNavLink href="#so-funktioniert-es">
|
||||
So funktioniert es
|
||||
</MobileNavLink>
|
||||
<MobileNavLink href="#vorteile">Vorteile</MobileNavLink>
|
||||
<MobileNavLink href="#partner-werden">Partner werden</MobileNavLink>
|
||||
</PopoverPanel>
|
||||
</Popover>
|
||||
)
|
||||
}
|
||||
|
||||
export function Header() {
|
||||
return (
|
||||
<header className="py-10">
|
||||
<Container>
|
||||
<nav className="relative z-50 flex justify-between">
|
||||
<div className="flex items-center md:gap-x-12">
|
||||
<Link href="/partner-modell" aria-label="GebOS">
|
||||
<Logo className="h-9 w-auto" />
|
||||
</Link>
|
||||
<div className="hidden md:flex md:gap-x-6">
|
||||
<NavLink href="#so-funktioniert-es">So funktioniert es</NavLink>
|
||||
<NavLink href="#vorteile">Vorteile</NavLink>
|
||||
<NavLink href="#partner-werden">Partner werden</NavLink>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-x-5 md:gap-x-8">
|
||||
<div className="hidden md:block">
|
||||
<NavLink href="#beratung">Beratungsgespräch</NavLink>
|
||||
</div>
|
||||
<Button href="#partner-werden" color="blue">
|
||||
<span>
|
||||
Partner <span className="hidden lg:inline">werden</span>
|
||||
</span>
|
||||
</Button>
|
||||
<div className="-mr-1 md:hidden">
|
||||
<MobileNavigation />
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</Container>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Button } from '@/components/Button'
|
||||
import { Container } from '@/components/Container'
|
||||
|
||||
export function Hero() {
|
||||
return (
|
||||
<Container className="pb-16 pt-20 text-center lg:pt-32">
|
||||
<h1 className="mx-auto max-w-4xl font-display text-5xl font-medium tracking-tight text-slate-900 sm:text-7xl">
|
||||
Bieten Sie Ihren Kunden eine{' '}
|
||||
<span className="relative whitespace-nowrap text-blue-600">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 418 42"
|
||||
className="absolute left-0 top-2/3 h-[0.58em] w-full fill-blue-300/70"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<path d="M203.371.916c-26.013-2.078-76.686 1.963-124.73 9.946L67.3 12.749C35.421 18.062 18.2 21.766 6.004 25.934 1.244 27.561.828 27.778.874 28.61c.07 1.214.828 1.121 9.595-1.176 9.072-2.377 17.15-3.92 39.246-7.496C123.565 7.986 157.869 4.492 195.942 5.046c7.461.108 19.25 1.696 19.17 2.582-.107 1.183-7.874 4.31-25.75 10.366-21.992 7.45-35.43 12.534-36.701 13.884-2.173 2.308-.202 4.407 4.442 4.734 2.654.187 3.263.157 15.593-.78 35.401-2.686 57.944-3.488 88.365-3.143 46.327.526 75.721 2.23 130.788 7.584 19.787 1.924 20.814 1.98 24.557 1.332l.066-.011c1.201-.203 1.53-1.825.399-2.335-2.911-1.31-4.893-1.604-22.048-3.261-57.509-5.556-87.871-7.36-132.059-7.842-23.239-.254-33.617-.116-50.627.674-11.629.54-42.371 2.494-46.696 2.967-2.359.259 8.133-3.625 26.504-9.81 23.239-7.825 27.934-10.149 28.304-14.005.417-4.348-3.529-6-16.878-7.066Z" />
|
||||
</svg>
|
||||
<span className="relative">UVI-Lösung</span>
|
||||
</span>{' '}
|
||||
an.
|
||||
</h1>
|
||||
<p className="mx-auto mt-6 max-w-2xl text-lg tracking-tight text-slate-700">
|
||||
Mit GebOS erweitern Elektro- und Sanitärbetriebe ihr Angebot um einen
|
||||
monatlichen UVI- und Verbrauchserfassungsservice. Sie beraten und
|
||||
installieren, GebOS übernimmt Plattform, Datenverarbeitung und
|
||||
Abrechnung.
|
||||
</p>
|
||||
<div className="mt-10 flex flex-col items-center justify-center gap-y-4 sm:flex-row sm:gap-x-6 sm:gap-y-0">
|
||||
<Button href="#partner-werden" color="blue">
|
||||
Partner werden
|
||||
</Button>
|
||||
<Button href="#beratung" variant="outline">
|
||||
Beratungsgespräch vereinbaren
|
||||
</Button>
|
||||
</div>
|
||||
<p className="mx-auto mt-10 max-w-xl text-sm tracking-tight text-slate-500">
|
||||
Für Elektro-, Sanitär- und Messdienst-nahe Betriebe mit Vermieter- und
|
||||
Hausverwaltungskunden.
|
||||
</p>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import { Container } from '@/components/Container'
|
||||
|
||||
const steps = [
|
||||
{
|
||||
title: 'Kunde fragt an',
|
||||
description:
|
||||
'Ein Vermieter oder eine Hausverwaltung fragt nach einer UVI-Lösung.',
|
||||
},
|
||||
{
|
||||
title: 'Sie bieten GebOS an',
|
||||
description: 'Sie empfehlen das GebOS UVI-Servicepaket.',
|
||||
},
|
||||
{
|
||||
title: 'Sie installieren',
|
||||
description:
|
||||
'Sie übernehmen Installation und Inbetriebnahme beim Kunden.',
|
||||
},
|
||||
{
|
||||
title: 'Sie verdienen mit',
|
||||
description:
|
||||
'GebOS vergütet Sie über eine Installationspauschale, Provision oder laufende Beteiligung.',
|
||||
},
|
||||
]
|
||||
|
||||
export function HowItWorks() {
|
||||
return (
|
||||
<section
|
||||
id="so-funktioniert-es"
|
||||
aria-labelledby="how-it-works-title"
|
||||
className="py-20 sm:py-32"
|
||||
>
|
||||
<Container>
|
||||
<div className="mx-auto max-w-2xl text-center">
|
||||
<p className="text-sm font-semibold uppercase tracking-wide text-blue-600">
|
||||
Das Partner-Modell
|
||||
</p>
|
||||
<h2
|
||||
id="how-it-works-title"
|
||||
className="mt-3 font-display text-3xl tracking-tight text-slate-900 sm:text-4xl"
|
||||
>
|
||||
So funktioniert das Partner-Modell
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-slate-700">
|
||||
Ein einfacher Ablauf in vier Schritten.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ol
|
||||
role="list"
|
||||
className="relative mx-auto mt-16 grid max-w-md grid-cols-1 gap-y-12 sm:max-w-3xl sm:grid-cols-2 sm:gap-x-12 lg:max-w-none lg:grid-cols-4 lg:gap-x-8"
|
||||
>
|
||||
{/* Connector line behind the step numbers on large screens. */}
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="absolute left-[12.5%] right-[12.5%] top-7 hidden h-px bg-slate-200 lg:block"
|
||||
/>
|
||||
|
||||
{steps.map((step, index) => (
|
||||
<li key={step.title} className="relative text-center lg:text-left">
|
||||
<span className="relative mx-auto flex h-14 w-14 items-center justify-center rounded-full bg-blue-600 font-display text-xl font-semibold text-white shadow-lg shadow-blue-600/25 lg:mx-0">
|
||||
{index + 1}
|
||||
</span>
|
||||
<h3 className="mt-6 font-display text-lg font-medium text-slate-900">
|
||||
{step.title}
|
||||
</h3>
|
||||
<p className="mt-2 text-base tracking-tight text-slate-600">
|
||||
{step.description}
|
||||
</p>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import Image from 'next/image'
|
||||
import clsx from 'clsx'
|
||||
|
||||
import logoGebOS from '@/images/logos/GebOS_Logo.png'
|
||||
|
||||
export function Logo({
|
||||
className,
|
||||
white = false,
|
||||
...props
|
||||
}: Omit<React.ComponentPropsWithoutRef<typeof Image>, 'src' | 'alt'> & {
|
||||
white?: boolean
|
||||
}) {
|
||||
return (
|
||||
<Image
|
||||
src={logoGebOS}
|
||||
alt="GebOS"
|
||||
priority
|
||||
className={clsx(white && 'brightness-0 invert', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
import { Button } from '@/components/Button'
|
||||
import { Container } from '@/components/Container'
|
||||
import screenshot from '@/images/screenshots/reporting.png'
|
||||
|
||||
export function Platform() {
|
||||
return (
|
||||
<section id="plattform" className="py-20 sm:py-32">
|
||||
<Container>
|
||||
<div className="relative overflow-hidden rounded-4xl bg-blue-600 px-6 py-16 sm:px-12 sm:py-20 lg:px-16">
|
||||
<div className="grid grid-cols-1 items-center gap-x-12 gap-y-12 lg:grid-cols-2">
|
||||
<div className="max-w-xl">
|
||||
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl">
|
||||
Die GebOS Platform
|
||||
</h2>
|
||||
<p className="mt-4 text-lg leading-8 tracking-tight text-blue-100">
|
||||
Verbrauchsdaten erfassen, UVI bereitstellen und Abrechnungen
|
||||
verwalten – alles an einem Ort.
|
||||
</p>
|
||||
<Button href="#" color="white" className="mt-8">
|
||||
Erkunden
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Placeholder UI interface */}
|
||||
<div className="overflow-hidden rounded-xl bg-white shadow-2xl ring-1 ring-slate-900/10">
|
||||
<div className="flex items-center gap-1.5 border-b border-slate-100 bg-slate-50 px-4 py-3">
|
||||
<span className="h-2.5 w-2.5 rounded-full bg-slate-300" />
|
||||
<span className="h-2.5 w-2.5 rounded-full bg-slate-300" />
|
||||
<span className="h-2.5 w-2.5 rounded-full bg-slate-300" />
|
||||
</div>
|
||||
<Image
|
||||
src={screenshot}
|
||||
alt="GebOS Platform – Benutzeroberfläche (Platzhalter)"
|
||||
className="w-full"
|
||||
sizes="(min-width: 1024px) 36rem, 100vw"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import { Container } from '@/components/Container'
|
||||
import { Logo } from '@/components/partner/Logo'
|
||||
|
||||
function CheckIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" className={className}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M16.704 5.29a1 1 0 0 1 .006 1.414l-7.5 7.56a1 1 0 0 1-1.42 0l-3.5-3.53a1 1 0 1 1 1.42-1.408l2.79 2.812 6.79-6.844a1 1 0 0 1 1.414-.005Z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
/** A step the installer already covers through their local presence. */
|
||||
function CoveredStep({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="flex items-center gap-x-4 rounded-2xl bg-slate-50 px-5 py-4 ring-1 ring-slate-900/5">
|
||||
<span className="flex h-8 w-8 flex-none items-center justify-center rounded-full bg-blue-50">
|
||||
<CheckIcon className="h-5 w-5 fill-blue-600" />
|
||||
</span>
|
||||
<span className="text-sm font-medium text-slate-700">{children}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/** The visual: the installer's service chain with a gap that GebOS fills. */
|
||||
function GapVisual() {
|
||||
return (
|
||||
<div className="relative mx-auto w-full max-w-md">
|
||||
<div className="rounded-3xl bg-white p-6 shadow-xl shadow-slate-900/5 ring-1 ring-slate-900/5 sm:p-8">
|
||||
<div className="mt-6 space-y-3">
|
||||
<CoveredStep>Beratung vor Ort</CoveredStep>
|
||||
<CoveredStep>Installation der Messtechnik</CoveredStep>
|
||||
|
||||
{/* The Lücke — a dashed slot the GebOS piece slots into. */}
|
||||
<div className="relative py-4">
|
||||
<div className="absolute -inset-x-1 inset-y-2 rounded-2xl border-2 border-dashed border-blue-300" />
|
||||
<span className="absolute -top-1 left-1/2 -translate-x-1/2 rounded-full bg-white px-2 text-xs font-semibold uppercase tracking-wide text-blue-500">
|
||||
Die Lücke
|
||||
</span>
|
||||
<div className="relative rounded-2xl bg-blue-600 p-5 shadow-lg shadow-blue-600/25">
|
||||
{/* Connector tabs that key the piece into the chain above & below. */}
|
||||
<span className="absolute -top-2 left-1/2 h-4 w-4 -translate-x-1/2 rounded-full bg-blue-600" />
|
||||
<span className="absolute -bottom-2 left-1/2 h-4 w-4 -translate-x-1/2 rounded-full bg-blue-600" />
|
||||
<Logo white className="h-6 w-auto" />
|
||||
<ul
|
||||
role="list"
|
||||
className="mt-3 space-y-1.5 text-sm font-medium text-blue-50"
|
||||
>
|
||||
{['Software-Plattform', 'Datenverarbeitung', 'Abrechnung'].map(
|
||||
(item) => (
|
||||
<li key={item} className="flex items-center gap-x-2">
|
||||
<span className="h-1.5 w-1.5 flex-none rounded-full bg-blue-200" />
|
||||
{item}
|
||||
</li>
|
||||
),
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CoveredStep>Monatliche UVI für die Mieter</CoveredStep>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function Problem() {
|
||||
return (
|
||||
<section
|
||||
id="ausgangslage"
|
||||
aria-labelledby="problem-title"
|
||||
className="bg-slate-50 py-20 sm:py-32"
|
||||
>
|
||||
<Container>
|
||||
<div className="grid grid-cols-1 items-center gap-x-16 gap-y-12 lg:grid-cols-2">
|
||||
<div>
|
||||
<h2
|
||||
id="problem-title"
|
||||
className="font-display text-3xl tracking-tight text-slate-900 sm:text-4xl"
|
||||
>
|
||||
Ihnen fehlt die passende Software?
|
||||
</h2>
|
||||
<p className="mt-6 text-lg tracking-tight text-slate-700">
|
||||
Sie erhalten Anfragen zur Umsetzung der neuen UVI-Pflicht, haben aber keine eigene Softwarelösung für Verbrauchsdaten, monatliche Informationen und digitale Abwicklung?
|
||||
</p>
|
||||
|
||||
<div className="mt-8 rounded-2xl border-l-4 border-blue-600 bg-blue-50/60 p-6">
|
||||
<p className="text-base text-slate-800">
|
||||
<span className="font-semibold text-slate-900">
|
||||
Mit uns:
|
||||
</span>{' '}
|
||||
Bleiben Sie Ansprechpartner vor Ort, während GebOS die digitale
|
||||
Infrastruktur bereitstellt.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<GapVisual />
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import { Container } from '@/components/Container'
|
||||
import { Logo } from '@/components/partner/Logo'
|
||||
|
||||
const gebosTasks = [
|
||||
'Softwareplattform',
|
||||
'Datenverarbeitung',
|
||||
'UVI-Service',
|
||||
'Monatliche Rechnung an Vermieter',
|
||||
'Technischer Support',
|
||||
]
|
||||
|
||||
const installerTasks = [
|
||||
'Beratung beim Kunden',
|
||||
'Installation vor Ort',
|
||||
'Inbetriebnahme',
|
||||
'Optional First-Level-Support',
|
||||
'Lokale Kundenbeziehung',
|
||||
]
|
||||
|
||||
function CheckIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" aria-hidden="true" className={className}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M16.704 5.29a1 1 0 0 1 .006 1.414l-7.5 7.56a1 1 0 0 1-1.42 0l-3.5-3.53a1 1 0 1 1 1.42-1.408l2.79 2.812 6.79-6.844a1 1 0 0 1 1.414-.005Z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function Responsibilities() {
|
||||
return (
|
||||
<section
|
||||
id="aufgabenteilung"
|
||||
aria-labelledby="responsibilities-title"
|
||||
className="bg-slate-50 py-20 sm:py-32"
|
||||
>
|
||||
<Container>
|
||||
<div className="mx-auto max-w-2xl text-center">
|
||||
<p className="text-sm font-semibold uppercase tracking-wide text-blue-600">
|
||||
Klare Aufgabenteilung
|
||||
</p>
|
||||
<h2
|
||||
id="responsibilities-title"
|
||||
className="mt-3 font-display text-3xl tracking-tight text-slate-900 sm:text-4xl"
|
||||
>
|
||||
Was übernimmt GebOS?
|
||||
</h2>
|
||||
<p className="mt-4 text-lg tracking-tight text-slate-700">
|
||||
Eine transparente Aufteilung: Sie behalten die Kundenbeziehung,
|
||||
GebOS übernimmt Technik und Abrechnung im Hintergrund.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="relative mx-auto mt-16 grid max-w-4xl grid-cols-1 gap-8 lg:grid-cols-2">
|
||||
{/* GebOS card — brand blue */}
|
||||
<div className="rounded-3xl bg-blue-600 p-8 shadow-xl shadow-blue-600/20">
|
||||
<div className="flex items-center gap-x-3">
|
||||
<Logo white className="h-7 w-auto" />
|
||||
<span className="text-sm font-medium text-blue-100">
|
||||
übernimmt
|
||||
</span>
|
||||
</div>
|
||||
<ul role="list" className="mt-8 space-y-4">
|
||||
{gebosTasks.map((task) => (
|
||||
<li key={task} className="flex items-center gap-x-3">
|
||||
<span className="flex h-7 w-7 flex-none items-center justify-center rounded-full bg-white/15">
|
||||
<CheckIcon className="h-5 w-5 fill-white" />
|
||||
</span>
|
||||
<span className="text-base font-medium text-white">
|
||||
{task}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Installer card — white */}
|
||||
<div className="rounded-3xl bg-white p-8 shadow-xl shadow-slate-900/5 ring-1 ring-slate-900/5">
|
||||
<p className="font-display text-xl font-medium text-slate-900">
|
||||
Sie als Installateur{' '}
|
||||
<span className="font-normal text-slate-500">übernehmen</span>
|
||||
</p>
|
||||
<ul role="list" className="mt-8 space-y-4">
|
||||
{installerTasks.map((task) => (
|
||||
<li key={task} className="flex items-center gap-x-3">
|
||||
<span className="flex h-7 w-7 flex-none items-center justify-center rounded-full bg-blue-50">
|
||||
<CheckIcon className="h-5 w-5 fill-blue-600" />
|
||||
</span>
|
||||
<span className="text-base font-medium text-slate-700">
|
||||
{task}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* The two halves combine into one solution. */}
|
||||
<span className="absolute left-1/2 top-1/2 z-10 flex h-12 w-12 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full bg-white font-display text-2xl font-semibold text-blue-600 shadow-lg ring-1 ring-slate-900/5">
|
||||
+
|
||||
</span>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { type ReactNode } from 'react'
|
||||
|
||||
import { Container } from '@/components/Container'
|
||||
|
||||
export function StatsSection({
|
||||
eyebrow,
|
||||
title,
|
||||
titleId,
|
||||
stats,
|
||||
children,
|
||||
}: {
|
||||
eyebrow?: string
|
||||
title: string
|
||||
titleId?: string
|
||||
stats: Array<{ value: string; label: string }>
|
||||
children?: ReactNode
|
||||
}) {
|
||||
return (
|
||||
<Container>
|
||||
<div className="mx-auto max-w-2xl lg:mx-0 lg:max-w-none">
|
||||
{eyebrow ? (
|
||||
<p className="text-sm font-semibold uppercase tracking-wide text-blue-600">
|
||||
{eyebrow}
|
||||
</p>
|
||||
) : null}
|
||||
<h2
|
||||
id={titleId}
|
||||
className="mt-3 text-pretty font-display text-3xl tracking-tight text-slate-900 sm:text-4xl"
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
<div className="mt-6 flex flex-col gap-x-8 gap-y-12 lg:flex-row">
|
||||
{children ? (
|
||||
<div className="lg:w-full lg:max-w-2xl lg:flex-auto">{children}</div>
|
||||
) : null}
|
||||
<div className="lg:flex lg:flex-auto lg:justify-center">
|
||||
<dl className="w-64 space-y-8 xl:w-80">
|
||||
{stats.map((stat) => (
|
||||
<div key={stat.label} className="flex flex-col-reverse gap-y-3">
|
||||
<dt className="text-base/7 text-slate-600">{stat.label}</dt>
|
||||
<dd className="font-display text-4xl font-semibold tracking-tight text-blue-600 sm:text-5xl">
|
||||
{stat.value}
|
||||
</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { GradientCallout } from '@/components/partner/GradientCallout'
|
||||
|
||||
export function WhatIsUvi() {
|
||||
return (
|
||||
<section
|
||||
id="was-ist-uvi"
|
||||
aria-labelledby="what-is-uvi-title"
|
||||
className="py-8 sm:py-10"
|
||||
>
|
||||
<GradientCallout
|
||||
title="Was ist UVI?"
|
||||
titleId="what-is-uvi-title"
|
||||
cta={{ href: '/was-ist-uvi', label: 'Mehr erfahren' }}
|
||||
>
|
||||
<p>
|
||||
Die Unterjährige Verbrauchsinformation (UVI) informiert Mieter
|
||||
monatlich über ihren Heiz- und Warmwasserverbrauch – verpflichtend bei
|
||||
fernablesbaren Messgeräten.
|
||||
</p>
|
||||
</GradientCallout>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 162 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 181 KiB |
|
After Width: | Height: | Size: 288 KiB |
|
After Width: | Height: | Size: 594 KiB |
@@ -0,0 +1,18 @@
|
||||
<svg width="136" height="48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#a)" fill="#334155">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M38.455 13.018c.004.01.01.02.012.03a.658.658 0 0 1 .022.164v8.586a.627.627 0 0 1-.311.543l-7.138 4.15v8.223a.627.627 0 0 1-.312.543l-14.899 8.66a.533.533 0 0 1-.108.044c-.014.006-.027.014-.042.018a.612.612 0 0 1-.318 0 .164.164 0 0 1-.028-.01l-.02-.01c-.035-.013-.07-.024-.103-.043L.311 35.257A.628.628 0 0 1 0 34.714V8.956a.68.68 0 0 1 .021-.163c.006-.019.016-.035.022-.053l.02-.053a.328.328 0 0 1 .02-.044c.012-.02.029-.037.043-.056.018-.025.033-.05.055-.073.018-.018.04-.03.06-.047.023-.018.044-.038.069-.053l7.45-4.33a.616.616 0 0 1 .62 0l7.45 4.33c.025.015.046.035.069.053l.021.016c.014.01.028.02.04.031a.345.345 0 0 1 .04.051l.015.022c.013.02.03.035.042.056.017.03.028.064.04.097l.01.022.012.03a.644.644 0 0 1 .021.164v16.088l6.208-3.608v-8.224a.64.64 0 0 1 .022-.163c.005-.019.015-.035.021-.053l.007-.02a.279.279 0 0 1 .076-.133c.018-.025.034-.05.055-.073.01-.01.02-.017.03-.025.01-.007.021-.014.03-.022l.036-.03a.26.26 0 0 1 .033-.023l7.45-4.33a.616.616 0 0 1 .62 0l7.45 4.33c.026.015.046.036.069.053l.022.016c.013.01.027.02.038.031a.327.327 0 0 1 .04.052l.016.021.016.02c.01.012.019.023.026.036a.522.522 0 0 1 .034.08l.006.017.01.022ZM9.322 30.453l6.196 3.54 13.652-7.867-6.201-3.605-13.647 7.932Zm20.476-5.409v-7.14l-6.208-3.607v7.14l6.207 3.607h.001Zm6.826-11.83-6.206-3.608-6.205 3.607 6.205 3.606 6.206-3.606Zm-27.933.434v15.726l6.208-3.609V10.04L8.69 13.648h.001Zm5.584-4.692L8.07 5.35 1.864 8.956l6.206 3.607 6.205-3.607ZM7.449 13.65l-6.208-3.61v24.31L14.9 42.29v-7.21l-7.135-4.076h-.002L7.759 31c-.025-.015-.045-.035-.067-.053a.277.277 0 0 1-.059-.045l-.002-.002c-.013-.013-.024-.029-.035-.044a.567.567 0 0 0-.016-.022l-.03-.038a.201.201 0 0 1-.016-.023l-.001-.002a.259.259 0 0 1-.023-.054l-.01-.024-.015-.033a.237.237 0 0 1-.014-.038.374.374 0 0 1-.01-.068l-.003-.025a.48.48 0 0 0-.004-.026c-.002-.014-.005-.029-.005-.044V13.65v.001Zm8.691 21.43v7.21l13.657-7.937V27.21L16.14 35.08v.001Zm14.9-10.037 6.208-3.608v-7.14l-6.208 3.61v7.14-.002Z" />
|
||||
<path d="M132.739 13.214H136V34.36h-3.261V13.214Zm-84.346 0h3.441V31.25h6.463v3.11h-9.904V13.216Z" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M68.576 20.525c.808.403 1.43.956 1.87 1.66v-1.902h3.261V34.36h-3.261v-1.903c-.439.705-1.062 1.259-1.87 1.66-.808.404-1.62.605-2.44.605-1.057 0-2.024-.196-2.902-.59a6.79 6.79 0 0 1-2.26-1.615 7.525 7.525 0 0 1-1.465-2.356 7.669 7.669 0 0 1-.524-2.84c0-.986.174-1.928.524-2.824a7.496 7.496 0 0 1 1.466-2.371 6.8 6.8 0 0 1 2.26-1.616c.877-.393 1.844-.59 2.902-.59.818 0 1.63.202 2.439.605Zm.733 9.938c.367-.416.651-.898.838-1.42.2-.552.302-1.134.3-1.721 0-.605-.1-1.18-.3-1.722a4.373 4.373 0 0 0-.838-1.42 4.056 4.056 0 0 0-1.302-.967 3.893 3.893 0 0 0-1.69-.362c-.62 0-1.178.12-1.677.362a4.105 4.105 0 0 0-1.286.967c-.36.403-.634.876-.823 1.42a5.182 5.182 0 0 0-.284 1.722c0 .604.094 1.178.284 1.72a4.17 4.17 0 0 0 .823 1.42c.36.404.788.726 1.286.968.524.247 1.097.37 1.676.362.618 0 1.182-.12 1.691-.362.495-.231.938-.56 1.302-.967Zm27.649-8.277c-.44-.705-1.063-1.258-1.87-1.661-.808-.403-1.62-.604-2.44-.604-1.057 0-2.024.196-2.902.589a6.8 6.8 0 0 0-2.26 1.616 7.492 7.492 0 0 0-1.465 2.37c-.35.901-.528 1.86-.524 2.826 0 1.007.174 1.953.524 2.84.338.869.836 1.668 1.466 2.355a6.79 6.79 0 0 0 2.26 1.616c.877.393 1.844.59 2.902.59.818 0 1.63-.202 2.439-.605.808-.402 1.43-.956 1.87-1.66v1.902h3.261V20.283h-3.261v1.903Zm-.3 6.857a4.368 4.368 0 0 1-.838 1.42 4.043 4.043 0 0 1-1.301.967 3.89 3.89 0 0 1-1.69.362c-.619 0-1.178-.12-1.677-.362a4.094 4.094 0 0 1-2.109-2.387 5.182 5.182 0 0 1-.285-1.721c0-.605.095-1.18.285-1.722a4.148 4.148 0 0 1 .823-1.42c.36-.404.798-.733 1.286-.967a3.794 3.794 0 0 1 1.676-.362c.618 0 1.182.12 1.69.362.51.242.943.565 1.302.967.36.403.639.876.839 1.42.198.543.299 1.117.299 1.722 0 .604-.1 1.178-.3 1.72Z" />
|
||||
<path
|
||||
d="M76.281 34.36h3.262V23.523h5.596v-3.24H76.28V34.36h.001Zm32.916-3.297 4.099-10.78h3.304l-5.354 14.077h-4.099l-5.353-14.077h3.303l4.1 10.78Z" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M123.714 19.92c-3.994 0-7.156 3.315-7.156 7.4 0 4.52 3.06 7.402 7.574 7.402 2.526 0 4.139-.975 6.109-3.098l-2.203-1.721c-.002 0-1.664 2.204-4.145 2.204-2.884 0-4.099-2.348-4.099-3.562h10.821c.568-4.65-2.46-8.624-6.901-8.624Zm-3.911 6.178c.025-.27.401-3.562 3.885-3.562s3.907 3.29 3.931 3.562h-7.816Z" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="a">
|
||||
<path fill="#fff" d="M0 0h136v48H0z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,17 @@
|
||||
<svg width="138" height="48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#a)" fill="#334155">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M30.316 5c3.984 0 7.213 3.256 7.213 7.273a7.272 7.272 0 0 1-4.771 6.845l5.814 10.462h3.98c.613 0 1.11.5 1.11 1.118 0 .618-.497 1.118-1.11 1.118H1.11c-.612 0-1.109-.5-1.109-1.118 0-.618.497-1.118 1.11-1.118h3.98l10.353-18.562a1.106 1.106 0 0 1 1.896-.063l5.948 9.189 1.85-2.809a7.28 7.28 0 0 1-2.035-5.062c0-4.017 3.23-7.273 7.214-7.273h-.001Zm-5.709 17.183 4.788 7.397h6.634l-7.457-13.418-3.965 6.021Zm2.14 7.397L16.48 13.72 7.635 29.58H26.747Zm8.702-17.307a5.172 5.172 0 0 1-3.728 4.98l-2.101-3.781a1.106 1.106 0 0 0-1.892-.072l-1.402 2.13a5.18 5.18 0 0 1-1.144-3.257c0-2.859 2.299-5.176 5.134-5.176 2.835 0 5.133 2.317 5.133 5.176Z" />
|
||||
<path
|
||||
d="M9.62 35.173c-.611 0-1.107.5-1.107 1.117s.496 1.116 1.107 1.116h24.42c.612 0 1.108-.5 1.108-1.116 0-.617-.496-1.117-1.107-1.117H9.62Zm8.513 5.59c-.613 0-1.11.5-1.11 1.119 0 .617.497 1.118 1.11 1.118h7.396c.612 0 1.109-.5 1.109-1.118 0-.618-.497-1.12-1.11-1.12h-7.395Z" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M120.027 21.871c-.982-1.25-2.453-1.923-4.347-1.923-2.984 0-6.049 2.528-6.049 6.786 0 4.258 3.065 6.786 6.049 6.786 1.894 0 3.365-.66 4.347-1.923v1.058c0 2.445-1.472 3.93-4.142 3.93-1.594 0-3.107-.524-4.428-1.334l-1.036 2.432c1.376.99 3.515 1.525 5.464 1.525 4.36 0 7.003-2.54 7.003-6.677v-12.24h-2.861v1.58Zm-7.467 4.863c0-2.225 1.444-4.08 3.855-4.08 2.303 0 3.857 1.773 3.857 4.08 0 2.308-1.554 4.08-3.857 4.08-2.411 0-3.855-1.867-3.855-4.08Zm-8.219-4.849c-.899-1.168-2.248-1.937-4.101-1.937-3.65 0-6.526 2.898-6.526 6.923s2.875 6.924 6.526 6.924c1.854 0 3.202-.755 4.101-1.923v1.58h2.848v-13.16h-2.848v1.593Zm-7.698 4.986c0-2.307 1.486-4.217 3.938-4.217 2.357 0 3.938 1.813 3.938 4.217s-1.581 4.218-3.938 4.218c-2.452 0-3.938-1.91-3.938-4.218ZM138 26.858c-.013-4.107-2.52-6.91-6.172-6.91-3.842 0-6.499 2.803-6.499 6.924 0 4.176 2.766 6.924 6.676 6.924 1.976 0 3.774-.48 5.368-1.854l-1.417-2.048c-1.076.865-2.466 1.388-3.774 1.388-1.853 0-3.501-.99-3.883-3.353h9.647c.027-.329.054-.7.054-1.07Zm-9.687-1.113c.3-1.923 1.43-3.242 3.46-3.242 1.813 0 2.998 1.195 3.311 3.242h-6.771Z" />
|
||||
<path
|
||||
d="m64.333 27.957-5.546-13.738H54.06v19.233h3.08V17.777L62.71 31.57h3.243l5.573-13.944v15.826h3.08V14.219h-4.729l-5.545 13.738h.001Zm16.871 5.495v-13.16h-2.86v13.16h2.86Zm12.182-13.133c-.654-.261-1.322-.37-2.194-.37-1.594 0-2.93.576-3.788 1.826V20.29h-2.82v13.16h2.848v-7.24c0-2.238 1.294-3.53 3.106-3.53.695 0 1.567.165 2.166.48l.682-2.842Zm-11.61-4.575c0-1.14-.886-2.033-2.017-2.033-1.13 0-1.99.893-1.99 2.033s.86 2.006 1.99 2.006c1.131 0 2.017-.866 2.017-2.006Z" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="a">
|
||||
<path fill="#fff" d="M0 0h138v48H0z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="127" height="48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="m3.31 28.903 14.75-15.816L14.749 10 0 25.816l3.31 3.087ZM5.792 39 20.54 23.184l-3.31-3.087L2.482 35.913 5.792 39Zm31.261-18.216a3.87 3.87 0 0 0-1.441-1.115c-.594-.276-1.166-.414-1.718-.414-.284 0-.572.025-.864.075a2.23 2.23 0 0 0-.79.289c-.234.142-.43.326-.59.551-.158.226-.237.514-.237.865 0 .3.062.552.188.752.125.2.309.376.551.527.242.15.53.288.865.413.334.126.71.255 1.128.389.602.2 1.229.422 1.88.664a7.03 7.03 0 0 1 1.78.965 5.07 5.07 0 0 1 1.329 1.492c.35.593.526 1.333.526 2.219 0 1.019-.188 1.9-.564 2.644a5.274 5.274 0 0 1-1.516 1.843 6.499 6.499 0 0 1-2.181 1.078 9.17 9.17 0 0 1-2.532.35c-1.27 0-2.499-.22-3.685-.663-1.187-.443-2.173-1.074-2.959-1.893l2.808-2.858c.435.535 1.007.982 1.717 1.341.71.36 1.417.54 2.119.54.317 0 .626-.034.927-.101.301-.067.564-.176.79-.326.225-.15.405-.351.539-.602.134-.25.2-.551.2-.902 0-.334-.083-.619-.25-.853a2.45 2.45 0 0 0-.715-.639 5.76 5.76 0 0 0-1.153-.526c-.46-.159-.982-.33-1.567-.514a14.963 14.963 0 0 1-1.667-.652 5.58 5.58 0 0 1-1.454-.965 4.471 4.471 0 0 1-1.028-1.43c-.259-.559-.388-1.24-.388-2.042 0-.986.2-1.83.601-2.532.39-.689.93-1.28 1.58-1.73a6.786 6.786 0 0 1 2.206-.99c.81-.208 1.645-.314 2.482-.314 1.002 0 2.026.184 3.07.552 1.045.368 1.96.91 2.746 1.63l-2.733 2.882Zm9.677 3.736v4.763c0 .585.113 1.023.338 1.316.226.292.631.439 1.216.439.2 0 .414-.017.64-.05.194-.025.383-.075.563-.15l.05 3.007c-.283.1-.643.188-1.077.264a7.63 7.63 0 0 1-1.304.112c-.836 0-1.538-.104-2.106-.313-.568-.209-1.023-.51-1.366-.902a3.54 3.54 0 0 1-.74-1.404 6.804 6.804 0 0 1-.225-1.818V24.52h-2.006v-3.084h1.98v-3.284h4.037v3.284h2.933v3.084H46.73Zm12.234 3.96h-.527c-.451 0-.906.021-1.366.063-.46.042-.87.122-1.228.238a2.27 2.27 0 0 0-.89.514c-.234.226-.351.523-.351.89 0 .234.054.435.163.602.108.167.246.3.413.401.167.1.36.171.577.213a3.3 3.3 0 0 0 .627.063c.835 0 1.474-.23 1.917-.69.443-.46.665-1.082.665-1.867v-.427Zm-7.546-5.34a7.2 7.2 0 0 1 2.57-1.579 8.805 8.805 0 0 1 2.995-.526c1.053 0 1.943.13 2.67.389.727.259 1.316.66 1.767 1.203.452.543.782 1.228.99 2.056.21.827.314 1.809.314 2.945v6.293h-3.76v-1.329h-.076c-.317.518-.798.92-1.441 1.203a5.125 5.125 0 0 1-2.093.426 6.403 6.403 0 0 1-1.555-.2 4.554 4.554 0 0 1-1.466-.652 3.53 3.53 0 0 1-1.09-1.203c-.285-.502-.427-1.12-.427-1.855 0-.903.247-1.63.74-2.181.493-.552 1.128-.978 1.905-1.279.777-.3 1.642-.501 2.595-.601.952-.1 1.88-.151 2.782-.151v-.2c0-.619-.217-1.074-.651-1.367-.435-.292-.97-.439-1.605-.439a3.99 3.99 0 0 0-1.692.377 5.4 5.4 0 0 0-1.392.902l-2.08-2.231v-.001Zm18.688 1.38v4.763c0 .585.112 1.023.338 1.316.225.292.63.439 1.216.439.2 0 .413-.017.639-.05.226-.034.414-.084.564-.15l.05 3.007a6.88 6.88 0 0 1-1.078.264c-.43.075-.866.112-1.303.112-.836 0-1.538-.104-2.106-.313-.568-.209-1.024-.51-1.366-.902a3.537 3.537 0 0 1-.74-1.404 6.808 6.808 0 0 1-.226-1.818V24.52H64.09v-3.084h1.98v-3.284h4.037v3.284h2.933v3.084H70.106Zm9.325-7.07c0 .318-.063.614-.188.89-.12.268-.29.51-.501.715a2.44 2.44 0 0 1-1.667.652c-.669 0-1.229-.222-1.68-.665a2.15 2.15 0 0 1-.677-1.592c0-.3.059-.589.176-.865.117-.275.284-.514.501-.714.217-.2.468-.364.752-.489s.593-.188.928-.188a2.445 2.445 0 0 1 1.667.652c.209.2.376.439.501.714.126.276.188.573.188.89ZM75.02 33.92V21.437h4.111v12.485H75.02v-.002Zm15.273-8.448a2.496 2.496 0 0 0-.953-.727 2.92 2.92 0 0 0-1.228-.275c-.435 0-.828.087-1.179.263a2.86 2.86 0 0 0-.902.702c-.25.292-.447.63-.59 1.015-.143.393-.215.81-.212 1.228 0 .435.067.844.2 1.229a3 3 0 0 0 .59 1.015c.258.293.568.522.927.69.36.167.765.25 1.216.25.418 0 .831-.08 1.24-.238.41-.159.74-.389.99-.69l2.282 2.783c-.518.502-1.186.894-2.005 1.178-.84.288-1.72.432-2.608.427a8.229 8.229 0 0 1-2.757-.452 6.361 6.361 0 0 1-2.219-1.316 6.18 6.18 0 0 1-1.479-2.093c-.36-.819-.539-1.746-.539-2.783 0-1.02.18-1.938.54-2.757a6.181 6.181 0 0 1 1.478-2.093 6.519 6.519 0 0 1 2.219-1.33 7.951 7.951 0 0 1 5.352.001c.41.142.786.317 1.128.526.343.21.64.439.89.69l-2.381 2.757Zm15.091 8.449-6.593-8.173h-.05v8.173h-4.212V16.17h4.212v7.22h.075l6.343-7.22h5.364l-7.646 8.173 8.098 9.577h-5.591v.001Zm11.206-16.47c0 .317-.062.613-.188.89-.12.268-.29.51-.501.714a2.445 2.445 0 0 1-1.667.652c-.669 0-1.229-.222-1.68-.665a2.152 2.152 0 0 1-.677-1.592c0-.3.059-.589.176-.865.117-.275.284-.514.501-.714.217-.2.468-.364.752-.489s.593-.188.928-.188a2.445 2.445 0 0 1 1.667.652c.209.2.376.439.501.714.126.276.188.573.188.89v.001Zm-4.412 16.47V21.436h4.111v12.485h-4.111Zm11.833-9.401v4.763c0 .585.112 1.023.338 1.316.226.292.631.439 1.216.439.2 0 .414-.017.639-.05.194-.024.384-.075.564-.15l.05 3.007a6.88 6.88 0 0 1-1.078.264c-.43.075-.866.112-1.303.112-.836 0-1.538-.104-2.106-.313-.568-.209-1.024-.51-1.366-.902a3.535 3.535 0 0 1-.74-1.404 6.84 6.84 0 0 1-.225-1.818V24.52h-2.006v-3.084h1.981v-3.284h4.036v3.284h2.933v3.084h-2.933Z"
|
||||
fill="#334155" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
@@ -0,0 +1,13 @@
|
||||
<svg width="158" height="48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#a)" fill="#334155">
|
||||
<path
|
||||
d="M55.423 18.178v-2.491H66.38v2.491h-4.076v13.875H59.47V18.178h-4.047Zm18.098 4.577a7.526 7.526 0 0 0-1.33-.116c-1.82 0-2.89 1.188-2.89 3.592v5.793h-2.69v-11.47h2.631v1.622h.058c.52-.985 1.677-2 3.21-2 .433 0 .722.03 1.011.059v2.52Zm12.866 9.269h-2.602v-1.448h-.058c-.78.985-2.024 1.883-3.932 1.883-2.573 0-5.493-2.057-5.493-6.17 0-3.65 2.573-6.083 5.695-6.083 1.908 0 3.065 1.013 3.76 1.911h.057v-1.564h2.602v11.471h-.03.001Zm-5.898-1.94c1.763 0 3.411-1.536 3.411-3.738 0-2.317-1.503-3.852-3.382-3.852-2.37 0-3.499 1.912-3.499 3.795 0 1.911 1.1 3.794 3.47 3.794v.001Zm9.021-9.531h2.66v1.449h.057c.896-1.304 2.226-1.825 3.498-1.825 2.371 0 4.453 1.564 4.453 5.243v6.604h-2.69v-6.46c0-1.97-.924-3.012-2.457-3.012-1.677 0-2.833 1.188-2.833 3.418v6.083H89.51v-11.5h.001Zm18.792 2.955c-.116-.84-.752-1.39-1.533-1.39-.925 0-1.445.579-1.445 1.216 0 .695.347 1.188 2.341 1.854 2.458.782 3.325 2.057 3.325 3.679 0 2.114-1.59 3.592-4.221 3.592-2.746 0-4.105-1.507-4.308-3.65h2.487c.115.956.694 1.68 1.879 1.68 1.012 0 1.59-.637 1.59-1.42 0-.868-.491-1.419-2.399-2.056-2.14-.695-3.239-1.767-3.239-3.563 0-1.883 1.475-3.273 3.903-3.273 2.458 0 3.759 1.448 4.048 3.33h-2.428v.001Zm5.03-8.227h2.978v2.723h-2.978v-2.723Zm.145 5.272h2.688v11.5h-2.688v-11.5Zm10.986 2.955c-.116-.84-.752-1.39-1.533-1.39-.925 0-1.445.579-1.445 1.216 0 .695.347 1.188 2.342 1.854 2.457.782 3.324 2.057 3.324 3.679 0 2.114-1.59 3.592-4.221 3.592-2.746 0-4.105-1.507-4.307-3.65h2.486c.116.956.694 1.68 1.879 1.68 1.012 0 1.59-.637 1.59-1.42 0-.868-.491-1.419-2.399-2.056-2.14-.695-3.238-1.767-3.238-3.563 0-1.883 1.474-3.273 3.903-3.273 2.457 0 3.758 1.448 4.047 3.33h-2.428v.001Zm3.845-2.955h1.445v-3.678h2.689v3.678h2.862v2.26h-2.891v5.127c0 1.564.492 1.999 1.59 1.999.463 0 .983-.087 1.388-.203v2.172c-.607.174-1.359.261-2.024.261-2.862 0-3.614-1.738-3.614-4.084v-5.272h-1.445v-2.26Zm14.311-.376c3.585 0 6.129 2.636 6.129 6.112 0 3.389-2.573 6.17-6.129 6.17-3.498 0-6.129-2.694-6.129-6.17 0-3.563 2.66-6.112 6.129-6.112Zm0 9.877c2.024 0 3.411-1.622 3.411-3.765 0-2.028-1.301-3.737-3.411-3.737-2.053 0-3.412 1.593-3.412 3.737 0 2.201 1.562 3.765 3.412 3.765Zm14.052-7.415c-1.822 0-2.891 1.188-2.891 3.592v5.793h-2.689v-11.47h2.631v1.622h.058c.52-.985 1.676-2 3.209-2 .433 0 .722.03 1.012.059v2.52a7.525 7.525 0 0 0-1.33-.116ZM20.816 37.731a1.39 1.39 0 0 1-1.388-1.39V11.37a1.389 1.389 0 0 1 2.369-.982c.26.26.406.614.406.982v24.97c0 .753-.636 1.39-1.387 1.39v.001Zm-5.783-12.484h-6.65a1.39 1.39 0 0 1-1.387-1.39c0-.783.607-1.391 1.388-1.391h6.65a1.39 1.39 0 1 1 0 2.78v.001Zm18.243 0h-6.678a1.39 1.39 0 0 1-1.388-1.39c0-.783.607-1.391 1.388-1.391h6.65a1.39 1.39 0 0 1 1.387 1.39c0 .782-.607 1.39-1.359 1.39v.001Z" />
|
||||
<path
|
||||
d="M20.816 44.712C9.338 44.712 0 35.356 0 23.856 0 12.356 9.338 3 20.816 3s20.816 9.356 20.816 20.856c0 11.5-9.338 20.856-20.816 20.856Zm0-38.931c-9.945 0-18.04 8.11-18.04 18.075s8.095 18.075 18.04 18.075c9.946 0 18.04-8.11 18.04-18.075S30.763 5.781 20.817 5.781h-.001Z" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="a">
|
||||
<path fill="#fff" d="M0 0h158v48H0z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
@@ -0,0 +1,13 @@
|
||||
<svg width="105" height="48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M18 4 0 10v19.5l6 2V37l18 6V11.5l-6 2V4ZM8 32.167 18 35.5V15.608l4-1.333v25.95L8 35.56v-3.393Z" fill="#334155" />
|
||||
<path
|
||||
d="M42.9 20.45V31h4.446V20.45h3.53v-3.392H39.39v3.393h3.51Zm10.205 4.798c0 3.978 2.3 6.006 6.376 6.006 3.9 0 6.396-1.853 6.396-6.045v-8.15H61.43v7.994c0 1.833-.39 2.73-1.95 2.73-1.58 0-1.97-.897-1.97-2.71v-8.015h-4.406v8.19Z"
|
||||
fill="#334155" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M68.965 31V17.058h5.558c4.017 0 5.733 1.794 5.733 4.777v.078c0 2.906-1.93 4.544-5.538 4.544h-1.346V31h-4.407Zm5.323-7.507h-.916v-3.14h.936c1.15 0 1.755.43 1.755 1.502v.078c0 1.033-.605 1.56-1.775 1.56Z"
|
||||
fill="#334155" />
|
||||
<path
|
||||
d="M82.563 31V17.058h4.427v10.53h5.07V31h-9.497Zm11.999-13.942V31h10.218v-3.393h-5.811v-2.086h4.368v-3.1h-4.368v-1.97h5.499v-3.393h-9.906Z"
|
||||
fill="#334155" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 967 B |
|
After Width: | Height: | Size: 181 KiB |
|
After Width: | Height: | Size: 179 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 186 KiB |
|
After Width: | Height: | Size: 149 KiB |
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||