init project

master
alex 2024-09-16 22:59:29 +02:00
commit fd1d16ccb7
65 changed files with 7540 additions and 0 deletions

122
CHANGELOG.md Normal file
View File

@ -0,0 +1,122 @@
# Changelog
## 2024-06-21
- Bump Headless UI dependency to v2.1
- Replaced `PopoverOverlay` with `PopoverBackdrop`
- Update to new data-attribute-based transition API
## 2024-06-18
- Update `prettier` and `prettier-plugin-tailwindcss` dependencies
## 2024-05-31
- Fix `npm audit` warnings
## 2024-05-07
- Bump Headless UI dependency to v2.0
## 2024-01-17
- Fix `sharp` dependency issues ([#1549](https://github.com/tailwindlabs/tailwindui-issues/issues/1549))
## 2024-01-16
- Replace Twitter with X
## 2024-01-10
- Update Tailwind CSS, Next.js, Prettier, TypeScript, ESLint, and other dependencies
- Fix indentation in `Button` component
## 2023-12-07
- Fix auth/404 pages being cut off on short screens ([#1528](https://github.com/tailwindlabs/tailwindui-issues/issues/1528))
## 2023-11-10
- Fix types in `Button` component
## 2023-09-07
- Added TypeScript version of template
## 2023-08-17
- Bump Headless UI dependency
## 2023-08-15
- Bump Next.js dependency
## 2023-07-31
- Port template to Next.js app router
## 2023-07-18
- Add 404 page
- Sort imports
## 2023-05-16
- Bump Next.js dependency
## 2023-04-11
- Bump Next.js dependency
## 2023-03-29
- Bump Tailwind CSS and Prettier dependencies
- Sort classes
## 2023-03-22
- Bump Headless UI dependency
## 2023-02-02
- Bump Headless UI dependency
## 2022-11-04
- Bump Tailwind CSS and Next.js dependencies
## 2022-09-27
- Update Headless UI, Next.js, and Autoprefixer dependencies
## 2022-09-09
- Update Next.js dependency
## 2022-09-07
- Update Headless UI dependency
## 2022-09-01
- Update Tailwind CSS, Next.js, Headless UI, ESLint, and other dependencies
## 2022-08-16
- Enable experimental Next.js `scrollRestoration` flag
## 2022-07-25
- Update Next.js and React dependencies
## 2022-07-13
- Improve wording of `aria-label` in `Plan` component
## 2022-07-06
- Replace `next/image` with `next/future/image`
## 2022-06-23
- Initial release

35
README.md Normal file
View File

@ -0,0 +1,35 @@
# Salient
Salient is a [Tailwind UI](https://tailwindui.com) site template built using [Tailwind CSS](https://tailwindcss.com) and [Next.js](https://nextjs.org).
## Getting started
To get started with this template, first install the npm dependencies:
```bash
npm install
```
Next, run the development server:
```bash
npm run dev
```
Finally, open [http://localhost:3000](http://localhost:3000) in your browser to view the website.
## Customizing
You can start editing this template by modifying the files in the `/src` folder. The site will auto-update as you edit these files.
## License
This site template is a commercial product and is licensed under the [Tailwind UI license](https://tailwindui.com/license).
## Learn more
To learn more about the technologies used in this site template, see the following resources:
- [Tailwind CSS](https://tailwindcss.com/docs) - the official Tailwind CSS documentation
- [Next.js](https://nextjs.org/docs) - the official Next.js documentation
- [Headless UI](https://headlessui.dev) - the official Headless UI documentation

32
deploy-production.sh Executable file
View File

@ -0,0 +1,32 @@
npm run build
# create zip file of build folder
zip -r build.zip build
# conncect to server to clear folder
ssh root@93.177.67.38 << EOF
cd /var/www/html/navilearn-landingpage/
rm -rf *
exit
EOF
# copy zip file to server
scp build.zip root@93.177.67.38:/var/www/html/navilearn-landingpage/
# connect to server
ssh root@93.177.67.38 << EOF
cd /var/www/html/navilearn-landingpage/
unzip build.zip
mv /var/www/html/navilearn-landingpage/build/* /var/www/html/navilearn-landingpage/
rm -rf /var/www/html/navilearn-landingpage/build
rm build.zip
exit
EOF
# remove zip file from local machine
rm build.zip

4
next.config.js Normal file
View File

@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {}
module.exports = nextConfig

5552
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

37
package.json Normal file
View File

@ -0,0 +1,37 @@
{
"name": "tailwindui-salient",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "PORT=50263 next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"browserslist": "defaults, not ie <= 11",
"dependencies": {
"@headlessui/react": "^2.1.0",
"@headlessui/tailwindcss": "^0.2.0",
"@heroicons/react": "^2.1.5",
"@tailwindcss/forms": "^0.5.3",
"@types/node": "^20.10.8",
"@types/react": "^18.2.47",
"@types/react-dom": "^18.2.18",
"autoprefixer": "^10.4.12",
"clsx": "^2.1.0",
"i18next": "^23.15.1",
"next": "^14.0.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^15.0.2",
"tailwindcss": "^3.4.1",
"typescript": "^5.3.3"
},
"devDependencies": {
"eslint": "^8.56.0",
"eslint-config-next": "^14.0.4",
"prettier": "^3.3.2",
"prettier-plugin-tailwindcss": "^0.6.5",
"sharp": "0.33.1"
}
}

6
postcss.config.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

6
prettier.config.js Normal file
View File

@ -0,0 +1,6 @@
/** @type {import('prettier').Options} */
module.exports = {
singleQuote: true,
semi: false,
plugins: ['prettier-plugin-tailwindcss'],
}

View File

@ -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">
Dont 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">&rarr;</span>
</span>
</Button>
</div>
</form>
</SlimLayout>
)
}

View File

@ -0,0 +1,65 @@
'use client'
import { Constants, EncodeStringToBase64 } from '@/app/utils'
import { Button } from '@/components/Button'
import { TextField } from '@/components/Fields'
export default function RegisterForm() {
return (
<form
onSubmit={async (event) => {
event.preventDefault()
const response = await fetch(
'https://navilearnapi.ex.umbach.dev/api/v1/organization',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: event.currentTarget.email.value,
password: EncodeStringToBase64(
event.currentTarget.password.value,
),
}),
},
)
if (!response.ok) {
console.error('Failed to register user!')
return
}
const data = await response.json()
// Redirect to the dashboard
window.location.href = `https://${data.OrganizationSubdomain}${Constants.API_URL}?s=${data.Session}`
}}
className="mt-10 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-2"
>
<TextField
className="col-span-full"
label="E-Mail"
name="email"
type="email"
autoComplete="email"
required
/>
<TextField
className="col-span-full"
label="Passwort"
name="password"
type="password"
autoComplete="new-password"
required
/>
<div className="col-span-full">
<Button type="submit" variant="solid" color="blue" className="w-full">
<span>Registrieren</span>
</Button>
</div>
</form>
)
}

View File

@ -0,0 +1,87 @@
import { type Metadata } from 'next'
import Link from 'next/link'
import { Logo } from '@/components/Logo'
import { SlimLayout } from '@/components/SlimLayout'
import RegisterForm from './form'
export const metadata: Metadata = {
title: 'Sign Up',
}
export default function Register() {
return (
<SlimLayout>
<Link href="/" aria-label="Home" className="flex items-center text-sm">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
className="size-5"
>
<path
fillRule="evenodd"
d="M11.78 5.22a.75.75 0 0 1 0 1.06L8.06 10l3.72 3.72a.75.75 0 1 1-1.06 1.06l-4.25-4.25a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0Z"
clipRule="evenodd"
/>
</svg>
<span>Zurück</span>
</Link>
<div className="mt-4 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">
Jetzt kostenlos registrieren
</h2>
<p className="mt-2 text-sm text-gray-700">
Testen Sie 30 Tage lang kostenlos NaviLearn.
</p>
<RegisterForm />
</SlimLayout>
)
}
/*
<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>
<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
/>
<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>
*/

BIN
src/app/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

45
src/app/layout.tsx Normal file
View File

@ -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 - NaviLearn',
default: 'NaviLearn',
},
description:
'NaviLearn ist Ihre digitale Plattform zur Wissensvermittlung, die hilft, wiederholte Fragen zu vermeiden und effizientes Lernen zu fördern.',
}
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>
)
}

27
src/app/not-found.tsx Normal file
View File

@ -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 couldnt find the page youre looking for.
</p>
<Button href="/" className="mt-10">
Go back home
</Button>
</SlimLayout>
)
}

27
src/app/page.tsx Normal file
View File

@ -0,0 +1,27 @@
import { CallToAction } from '@/components/CallToAction'
import { Faqs } from '@/components/Faqs'
import { Footer } from '@/components/Footer'
import { Header } from '@/components/Header'
import { Hero } from '@/components/Hero'
import { Pricing } from '@/components/Pricing'
import { PrimaryFeatures } from '@/components/PrimaryFeatures'
import { SecondaryFeatures } from '@/components/SecondaryFeatures'
import { Testimonials } from '@/components/Testimonials'
export default function Home() {
return (
<>
<Header />
<main>
<Hero />
<PrimaryFeatures />
<SecondaryFeatures />
<Pricing />
<Faqs />
<CallToAction />
</main>
<Footer />
</>
)
}

12
src/app/utils.tsx Normal file
View File

@ -0,0 +1,12 @@
import { Buffer } from 'buffer'
export const Constants = {
API_URL: '.ex.umbach.dev',
ROUTES: {
REGISTER: '/register',
},
}
export function EncodeStringToBase64(value: string) {
return Buffer.from(value).toString('base64')
}

63
src/components/Button.tsx Normal file
View File

@ -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} />
)
}

View File

@ -0,0 +1,42 @@
import Image from 'next/image'
import { Button } from '@/components/Button'
import { Container } from '@/components/Container'
import backgroundImage from '@/images/background-call-to-action.jpg'
import { Constants } from '@/app/utils'
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">
Starten Sie noch heute
</h2>
<p className="mt-4 text-lg tracking-tight text-white">
Es ist Zeit, wiederholende Fragen hinter sich zu lassen und
stattdessen mit intelligenten Lösungen effizienter zu arbeiten.
</p>
<Button
href={Constants.ROUTES.REGISTER}
color="white"
className="mt-10"
>
Kostenlos testen
</Button>
</div>
</Container>
</section>
)
}

View File

@ -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}
/>
)
}

76
src/components/Faqs.tsx Normal file
View File

@ -0,0 +1,76 @@
import Image from 'next/image'
import { Container } from '@/components/Container'
import backgroundImage from '@/images/background-faqs.jpg'
const faqs = [
[
{
question: 'Wie installiere ich die Software?',
answer:
'NaviLearn ist ein Saas-Produkt, das keine Installation erfordert. Sie können sofort in Ihrem Browser loslegen.',
},
{
question: 'Wie füge ich neue Mitarbeiter hinzu?',
answer:
'Sie können neue Mitarbeiter über die Schaltfläche in der Teamübersicht hinzufügen.',
},
{
question: 'Kann ich die Software auf mehreren Geräten verwenden?',
answer:
'Ja, Sie können NaviLearn auf beliebig vielen Geräten innerhalb eines Benutzerkontos verwenden.',
},
],
]
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"
>
Häufig gestellte Fragen
</h2>
<p className="mt-4 text-lg tracking-tight text-slate-700">
Falls Sie hier keine Antwort auf Ihre Frage finden, zögern Sie
nicht, uns eine E-Mail zu schreiben.
</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-1"
>
{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>
)
}

47
src/components/Fields.tsx Normal file
View File

@ -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>
)
}

24
src/components/Footer.tsx Normal file
View File

@ -0,0 +1,24 @@
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-center text-sm" aria-label="quick links">
<div className="-my-1 flex flex-col justify-center gap-x-6 sm:flex-row">
<NavLink href="#features">Funktionen</NavLink>
<NavLink href="#pricing">Preise</NavLink>
</div>
</nav>
</div>
<div className="flex flex-col items-center border-t border-slate-400/10 py-10">
<p className="mt-6 text-sm text-slate-500 sm:mt-0">NaviLearn</p>
</div>
</Container>
</footer>
)
}

114
src/components/Header.tsx Normal file
View File

@ -0,0 +1,114 @@
'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'
import { Constants } from '@/app/utils'
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">Funktionen</MobileNavLink>
<MobileNavLink href="#testimonials">Kundenbewertungen</MobileNavLink>
<MobileNavLink href="#pricing">Preise</MobileNavLink>
<hr className="m-2 border-slate-300/40" />
<MobileNavLink href={Constants.ROUTES.REGISTER}>
Registrieren
</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-5 w-auto sm:h-10" />
</Link>
<div className="hidden md:flex md:gap-x-6">
<NavLink href="#features">Funktionen</NavLink>
<NavLink href="#pricing">Preise</NavLink>
</div>
</div>
<div className="flex items-center gap-x-5 md:gap-x-8">
<Button href="/register" color="blue">
<span>Jetzt loslegen</span>
</Button>
<div className="-mr-1 md:hidden">
<MobileNavigation />
</div>
</div>
</nav>
</Container>
</header>
)
}

79
src/components/Hero.tsx Normal file
View File

@ -0,0 +1,79 @@
// import Image from 'next/image'
import { Constants } from '@/app/utils'
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-20 pt-20 text-center lg:pb-52 lg:pt-52">
<h1 className="mx-auto max-w-5xl font-display text-5xl font-medium tracking-tight text-slate-900 sm:text-7xl">
Einfaches und reibungsloses{' '}
<span className="relative whitespace-nowrap text-blue-600">
<svg
aria-hidden="true"
viewBox="0 0 418 42"
className="absolute left-0 top-24 h-[0.58em] w-full fill-blue-300/70 sm:top-2/3 sm:top-3/4"
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 text-wrap">Mitarbeiter-Onboarding.</span>
</span>
</h1>
<p className="mx-auto mt-6 max-w-2xl text-lg tracking-tight text-slate-700">
Erstellen Sie strukturierte Lektionen für das eigenständige Lernen neuer
Mitarbeiter, um wiederholte Erklärungen zu vermeiden und den
Onboarding-Prozess effizienter zu gestalten.
</p>
<div className="mt-10 flex justify-center gap-x-6">
<Button href={Constants.ROUTES.REGISTER}>Kostenlos testen</Button>
</div>
</Container>
)
}
/*
<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>
*/

6
src/components/Logo.tsx Normal file
View File

@ -0,0 +1,6 @@
import logoNavilearn from '@/images/logos/navilearn.svg'
import Image from 'next/image'
export function Logo(props: any) {
return <Image src={logoNavilearn} alt="logo" unoptimized {...props} />
}

View File

@ -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>
)
}

208
src/components/Pricing.tsx Normal file
View File

@ -0,0 +1,208 @@
import clsx from 'clsx'
import { Button } from '@/components/Button'
import { Container } from '@/components/Container'
import { CheckIcon as CheckIcon2 } from '@heroicons/react/20/solid'
import { Constants } from '@/app/utils'
const includedFeatures = [
'Lektionen erstellen und verwalten',
'KI Chat',
'Board für Fragen und Antworten',
]
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" className="bg-slate-900 py-24 sm:py-32">
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="md:text-center">
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl">
Einfache{' '}
<span className="relative whitespace-nowrap">
<SwirlyDoodle className="absolute left-0 top-1/2 h-[1em] w-full fill-blue-400" />
<span className="relative">Preisgestaltung</span>
</span>
</h2>
<div className="mx-auto max-w-4xl">
<p className="mt-4 text-lg text-slate-400">
Unser Produkt befindet sich aktuell in der Testphase, daher bieten
wir nur ein einziges Preismodell an.
</p>
</div>
</div>
<div className="mx-auto mt-16 max-w-2xl rounded-3xl ring-1 ring-gray-700 sm:mt-20 lg:mx-0 lg:flex lg:max-w-none">
<div className="p-8 sm:p-10 lg:flex-auto">
<h3 className="text-2xl font-bold tracking-tight text-white">
NaviLearn Mitgliedschaft
</h3>
<p className="mt-6 text-base leading-7 text-slate-100">
Bringen Sie Ihren Onboarding-Prozess auf das nächste Level und
lassen Sie wiederholte Erklärungen der Vergangenheit angehören.
</p>
<div className="mt-10 flex items-center gap-x-4">
<h4 className="flex-none text-sm font-semibold leading-6 text-indigo-400">
Was Sie erhalten
</h4>
<div className="h-px flex-auto bg-gray-700" />
</div>
<ul
role="list"
className="mt-8 grid grid-cols-1 gap-4 text-sm leading-6 text-gray-600 sm:grid-cols-2 sm:gap-6"
>
{includedFeatures.map((feature) => (
<li key={feature} className="flex gap-x-3 text-slate-100">
<CheckIcon2
aria-hidden="true"
className="h-6 w-5 flex-none text-indigo-400"
/>
{feature}
</li>
))}
</ul>
</div>
<div className="-mt-2 p-2 lg:mt-0 lg:w-full lg:max-w-md lg:flex-shrink-0">
<div className="rounded-2xl bg-blue-600 py-10 text-center ring-1 ring-inset ring-gray-900/5 lg:flex lg:flex-col lg:justify-center lg:py-16">
<div className="mx-auto max-w-xs px-8">
<p className="text-base font-semibold text-slate-100">
Für nur
</p>
<p className="mt-6 flex items-baseline justify-center gap-x-2">
<span className="text-5xl font-bold tracking-tight text-white">
49
</span>
<span className="text-xs font-semibold leading-6 tracking-wide text-slate-100">
/MONAT
</span>
</p>
<Button
href={Constants.ROUTES.REGISTER}
variant="solid"
color="white"
className="mt-8 block w-full"
aria-label=""
>
Kostenlos testen
</Button>
<p className="mt-6 text-xs leading-5 text-slate-200">
Bis zum Ende der Beta-Phase können Sie NaviLearn
uneingeschränkt kostenlos nutzen.
</p>
</div>
</div>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,156 @@
'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 screenshotLesson from '@/images/screenshots/Frame 177 (4).png'
import screenshotEditor from '@/images/screenshots/Frame 178 (1).png'
import screenshotAiChat from '@/images/screenshots/Frame 179.png'
// import screenshotReporting from '@/images/screenshots/reporting.png'
import screenshotVatReturns from '@/images/screenshots/vat-returns.png'
const features = [
{
title: 'Lektionen',
description:
'Erstellen Sie ansprechende Lektionen, die Ihre Mitarbeiter mit Freude durchlaufen.',
image: screenshotLesson,
},
{
title: 'Editor',
description:
'Fügen Sie mit unserem Editor Inhalte zu Ihrer Lektion hinzu und bearbeiten Sie diese jederzeit nach Bedarf.',
image: screenshotEditor,
},
{
title: 'KI Chat',
description:
'Unser Chatbot kennt den Inhalt aller Lektionen und bietet präzise Antworten auf spezifische Fragen.',
image: screenshotAiChat,
},
]
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">
Alles, was Sie benötigen, um Ihr Onboarding auf ein neues Level zu
heben.
</h2>
<p className="mt-6 max-w-3xl text-lg tracking-tight text-blue-100 md:mx-auto">
Mit speziell fürs Mitarbeiter-Onboarding entwickelten Funktionen
können Sie im Handumdrehen eigene Lektionen erstellen.
</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>
)
}

View File

@ -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'
import sc1 from '@/images/screenshots/Screenshot from 2024-09-16 22-31-20.png'
import sc from '@/images/screenshots/Screenshot from 2024-09-16 22-27-51.png'
import sc3 from '@/images/screenshots/Screenshot from 2024-09-16 22-36-08.png'
interface Feature {
name: React.ReactNode
summary: string
description: string
image: ImageProps['src']
icon: React.ComponentType
}
const features: Array<Feature> = [
{
name: 'Mitarbeiterschulung & Onboarding',
summary: ' Einführung ins Unternehmen',
description:
'Machen Sie Ihre neuen Mitarbeiter durch Lektionen mit Ihrer Marke und Unternehmenskultur vertraut.',
image: sc1,
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: 'Alltägliche Aufgaben',
summary: 'Reinigung der Kaffeemaschine',
description:
'Erklären Sie Ihren Mitarbeitern einmal ausführlich die richtige Reinigung der Kaffeemaschine das spart Zeit und sorgt für zufriedene Kollegen.',
image: sc,
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: 'Fragen & Antworten',
summary: 'Übersicht häufig gestellter Fragen und Antworten.',
description:
'Dieses Board bietet Ihren Mitarbeitern sofortige Antworten auf häufige Fragen und die Möglichkeit, eigene Fragen hinzuzufügen.',
image: sc3,
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-xl md:text-center">
<h2 className="font-display text-3xl tracking-tight text-slate-900 sm:text-4xl">
Vereinfachen Sie alltägliche Aufgaben im Unternehmen.
</h2>
<p className="mt-4 text-lg tracking-tight text-slate-700">
Immer wiederkehrende Fragen gehören der Vergangenheit an.
</p>
</div>
<FeaturesMobile />
<FeaturesDesktop />
</Container>
</section>
)
}

View File

@ -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>
</>
)
}

View File

@ -0,0 +1,143 @@
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 cant help but wonder if its really doing the things the government expects me to do.',
author: {
name: 'Sheryl Berge',
role: 'CEO at Lynch LLC',
image: avatarImage1,
},
},
{
content:
'Im trying to get a hold of someone in support, Im 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 doesnt 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 dont do at all with TaxPal. Suspicious but I cant say I dont 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 dont 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 Ive 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="Bewertungen von Unternehmen"
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">
Von zahlreichen Unternehmen geschätzt.
</h2>
<p className="mt-4 text-lg tracking-tight text-slate-700">
Erfahren Sie, wie andere Unternehmen NaviLearn erfolgreich
einsetzen.
</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>
)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,15 @@
<svg width="6377" height="1318" viewBox="0 0 6377 1318" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1609.87 241.727V969H1566.54L1102.76 322.338H1098.5V969H1054.11V241.727H1097.79L1561.57 889.099H1565.83V241.727H1609.87ZM1791.68 969H1744.81L2007.24 241.727H2058.38L2320.8 969H2273.93L2034.58 298.901H2031.03L1791.68 969ZM1858.09 695.207H2207.52V736.401H1858.09V695.207ZM2360.04 241.727L2598.68 911.827H2603.65L2842.29 241.727H2889.16L2626.73 969H2575.6L2313.17 241.727H2360.04ZM3069.21 241.727V969H3024.82V241.727H3069.21ZM3279.7 969V241.727H3324.09V927.807H3679.2V969H3279.7ZM3842.2 969V241.727H4247.03V282.92H3886.59V584.412H4225.37V625.605H3886.59V927.807H4255.55V969H3842.2ZM4403.01 969H4356.14L4618.57 241.727H4669.7L4932.13 969H4885.26L4645.91 298.901H4642.36L4403.01 969ZM4469.42 695.207H4818.85V736.401H4469.42V695.207ZM5067.79 969V241.727H5291.86C5337.79 241.727 5377.33 250.723 5410.47 268.716C5443.61 286.708 5469.06 311.685 5486.82 343.645C5504.58 375.368 5513.45 412.3 5513.45 454.44C5513.45 496.107 5504.58 532.802 5486.82 564.526C5469.06 596.012 5443.61 620.634 5410.47 638.389C5377.56 656.145 5338.15 665.023 5292.22 665.023H5091.58V623.474H5291.15C5328.56 623.474 5360.52 616.491 5387.03 602.523C5413.55 588.555 5433.91 569.024 5448.11 543.929C5462.32 518.598 5469.42 488.768 5469.42 454.44C5469.42 419.876 5462.32 389.81 5448.11 364.241C5433.91 338.437 5413.43 318.432 5386.68 304.227C5360.16 290.023 5328.2 282.92 5290.8 282.92H5112.17V969H5067.79ZM5366.44 639.455L5545.41 969H5494.28L5316.37 639.455H5366.44ZM6246.59 241.727V969H6203.26L5739.48 322.338H5735.22V969H5690.83V241.727H5734.51L6198.29 889.099H6202.55V241.727H6246.59Z" fill="black"/>
<path d="M20.8574 133.904V1058.55L351.088 786.543L683.925 1058.55V133.904H20.8574Z" fill="url(#paint0_linear_904_2)"/>
<path d="M15 1047.85V145C15 139.477 19.4772 135 25 135H676.304C681.827 135 686.304 139.477 686.304 145V1047.85C686.304 1056.38 676.311 1060.99 669.818 1055.46L376.596 805.588C361.646 792.848 339.658 792.848 324.708 805.588L31.486 1055.46C24.9936 1060.99 15 1056.38 15 1047.85Z" stroke="black" stroke-width="30" stroke-linejoin="round"/>
<rect x="33.8906" y="1038.85" width="852.121" height="26.0708" transform="rotate(-40.5144 33.8906 1038.85)" fill="black"/>
<rect x="0.113281" y="837.749" width="896.161" height="26.0708" rx="5" transform="rotate(-40.5144 0.113281 837.749)" fill="black"/>
<rect x="0.449219" y="611.988" width="752.012" height="26.0708" rx="5" transform="rotate(-40.5144 0.449219 611.988)" fill="black"/>
<rect x="0.349609" y="387.94" width="409.518" height="26.0708" rx="5" transform="rotate(-40.5144 0.349609 387.94)" fill="black"/>
<defs>
<linearGradient id="paint0_linear_904_2" x1="664.828" y1="950.479" x2="170.258" y2="138.123" gradientUnits="userSpaceOnUse">
<stop stop-color="#0070E0"/>
<stop offset="1" stop-color="#449BF2"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -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

View File

@ -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

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

3
src/styles/tailwind.css Normal file
View File

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

37
tailwind.config.ts Normal file
View File

@ -0,0 +1,37 @@
import headlessuiPlugin from '@headlessui/tailwindcss'
import formsPlugin from '@tailwindcss/forms'
import { type Config } from 'tailwindcss'
export default {
content: ['./src/**/*.{js,jsx,ts,tsx}'],
theme: {
fontSize: {
xs: ['0.75rem', { lineHeight: '1rem' }],
sm: ['0.875rem', { lineHeight: '1.5rem' }],
base: ['1rem', { lineHeight: '1.75rem' }],
lg: ['1.125rem', { lineHeight: '2rem' }],
xl: ['1.25rem', { lineHeight: '2rem' }],
'2xl': ['1.5rem', { lineHeight: '2rem' }],
'3xl': ['2rem', { lineHeight: '2.5rem' }],
'4xl': ['2.5rem', { lineHeight: '3.5rem' }],
'5xl': ['3rem', { lineHeight: '3.5rem' }],
'6xl': ['3.75rem', { lineHeight: '1' }],
'7xl': ['4.5rem', { lineHeight: '1.1' }],
'8xl': ['6rem', { lineHeight: '1' }],
'9xl': ['8rem', { lineHeight: '1' }],
},
extend: {
borderRadius: {
'4xl': '2rem',
},
fontFamily: {
sans: 'var(--font-inter)',
display: 'var(--font-lexend)',
},
maxWidth: {
'2xl': '40rem',
},
},
},
plugins: [formsPlugin, headlessuiPlugin],
} satisfies Config

28
tsconfig.json Normal file
View File

@ -0,0 +1,28 @@
{
"compilerOptions": {
"target": "es6",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}