mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-12 13:45:03 +00:00
initial setup, ztdl-login, core
This commit is contained in:
56
apps/login/ui/AddressBar.tsx
Normal file
56
apps/login/ui/AddressBar.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { usePathname } from 'next/navigation';
|
||||
|
||||
export function AddressBar() {
|
||||
const pathname = usePathname();
|
||||
|
||||
return (
|
||||
<div className="flex items-center space-x-2 p-3.5 lg:px-5 lg:py-3">
|
||||
<div className="text-gray-600">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-4"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="flex space-x-1 text-sm font-medium">
|
||||
<div>
|
||||
<span className="px-2 text-gray-500">acme.com</span>
|
||||
</div>
|
||||
{pathname ? (
|
||||
<>
|
||||
<span className="text-gray-600">/</span>
|
||||
{pathname
|
||||
.split('/')
|
||||
.slice(1)
|
||||
.map((segment) => {
|
||||
return (
|
||||
<React.Fragment key={segment}>
|
||||
<span>
|
||||
<span
|
||||
key={segment}
|
||||
className="animate-[highlight_1s_ease-in-out_1] rounded-full px-1.5 py-0.5 text-gray-100"
|
||||
>
|
||||
{segment}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span className="text-gray-600">/</span>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
82
apps/login/ui/Boundary.tsx
Normal file
82
apps/login/ui/Boundary.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
|
||||
const Label = ({
|
||||
children,
|
||||
animateRerendering,
|
||||
color,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
animateRerendering?: boolean;
|
||||
color?: 'default' | 'pink' | 'blue' | 'violet' | 'cyan' | 'orange';
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={clsx('rounded-full px-1.5 shadow-[0_0_1px_3px_black]', {
|
||||
'bg-gray-800 text-gray-500': color === 'default',
|
||||
'bg-vercel-pink text-pink-100': color === 'pink',
|
||||
'bg-vercel-blue text-blue-100': color === 'blue',
|
||||
'bg-vercel-cyan text-cyan-100': color === 'cyan',
|
||||
'bg-vercel-violet text-violet-100': color === 'violet',
|
||||
'bg-vercel-orange text-orange-100': color === 'orange',
|
||||
'animate-[highlight_1s_ease-in-out_1]': animateRerendering,
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export const Boundary = ({
|
||||
children,
|
||||
labels = ['children'],
|
||||
size = 'default',
|
||||
color = 'default',
|
||||
animateRerendering = true,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
labels?: string[];
|
||||
size?: 'small' | 'default';
|
||||
color?: 'default' | 'pink' | 'blue' | 'violet' | 'cyan' | 'orange';
|
||||
animateRerendering?: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={clsx('relative rounded-lg border border-dashed', {
|
||||
'p-3 lg:p-5': size === 'small',
|
||||
'p-4 lg:p-9': size === 'default',
|
||||
'border-gray-700': color === 'default',
|
||||
'border-vercel-pink': color === 'pink',
|
||||
'border-vercel-blue': color === 'blue',
|
||||
'border-vercel-cyan': color === 'cyan',
|
||||
'border-vercel-violet': color === 'violet',
|
||||
'border-vercel-orange': color === 'orange',
|
||||
'animate-[rerender_1s_ease-in-out_1] text-vercel-pink':
|
||||
animateRerendering,
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
'absolute -top-2.5 flex space-x-1 text-[9px] uppercase leading-4 tracking-widest',
|
||||
{
|
||||
'left-3 lg:left-5': size === 'small',
|
||||
'left-4 lg:left-9': size === 'default',
|
||||
},
|
||||
)}
|
||||
>
|
||||
{labels.map((label) => {
|
||||
return (
|
||||
<Label
|
||||
key={label}
|
||||
color={color}
|
||||
animateRerendering={animateRerendering}
|
||||
>
|
||||
{label}
|
||||
</Label>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
80
apps/login/ui/Button.tsx
Normal file
80
apps/login/ui/Button.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
import clsx from 'clsx';
|
||||
import React, {
|
||||
ButtonHTMLAttributes,
|
||||
DetailedHTMLProps,
|
||||
forwardRef,
|
||||
} from 'react';
|
||||
|
||||
export enum ButtonSizes {
|
||||
Small = 'Small',
|
||||
Large = 'Large',
|
||||
}
|
||||
|
||||
export enum ButtonVariants {
|
||||
Primary = 'Primary',
|
||||
Secondary = 'Secondary',
|
||||
Destructive = 'Destructive',
|
||||
}
|
||||
|
||||
export enum ButtonColors {
|
||||
Neutral = 'Neutral',
|
||||
Primary = 'Primary',
|
||||
Warn = 'Warn',
|
||||
}
|
||||
|
||||
export type ButtonProps = DetailedHTMLProps<
|
||||
ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
HTMLButtonElement
|
||||
> & {
|
||||
size?: ButtonSizes;
|
||||
variant?: ButtonVariants;
|
||||
color?: ButtonColors;
|
||||
};
|
||||
|
||||
export const getButtonClasses = (
|
||||
size: ButtonSizes,
|
||||
variant: ButtonVariants,
|
||||
color: ButtonColors,
|
||||
) =>
|
||||
clsx({
|
||||
'box-border font-normal leading-36px text-14px inline-flex items-center rounded-md focus:outline-none transition-colors transition-shadow duration-300':
|
||||
true,
|
||||
'shadow hover:shadow-xl active:shadow-xl disabled:border-none disabled:bg-gray-300 disabled:text-gray-600 disabled:cursor-not-allowed disabled:dark:bg-gray-800 disabled:dark:text-gray-900':
|
||||
variant === ButtonVariants.Primary,
|
||||
'bg-primary-light-500 dark:bg-primary-dark-500 hover:bg-primary-light-400 hover:dark:bg-primary-dark-400 text-primary-light-contrast dark:text-primary-dark-contrast':
|
||||
variant === ButtonVariants.Primary && color !== ButtonColors.Warn,
|
||||
'bg-warn-light-500 dark:bg-warn-dark-500 hover:bg-warn-light-400 hover:dark:bg-warn-dark-400 text-white dark:text-white':
|
||||
variant === ButtonVariants.Primary && color === ButtonColors.Warn,
|
||||
'border border-button-light-border dark:border-button-dark-border text-gray-950 hover:bg-gray-500 hover:bg-opacity-20 hover:dark:bg-white hover:dark:bg-opacity-10 focus:bg-gray-500 focus:bg-opacity-20 focus:dark:bg-white focus:dark:bg-opacity-10 dark:text-white disabled:text-gray-600 disabled:hover:bg-transparent disabled:dark:hover:bg-transparent disabled:cursor-not-allowed disabled:dark:text-gray-900':
|
||||
variant === ButtonVariants.Secondary,
|
||||
'border border-button-light-border dark:border-button-dark-border text-warn-light-500 dark:text-warn-dark-500 hover:bg-warn-light-500 hover:bg-opacity-10 dark:hover:bg-warn-light-500 dark:hover:bg-opacity-10 focus:bg-warn-light-500 focus:bg-opacity-20 dark:focus:bg-warn-light-500 dark:focus:bg-opacity-20':
|
||||
color === ButtonColors.Warn && variant !== ButtonVariants.Primary,
|
||||
'px-16 py-2': size === ButtonSizes.Large,
|
||||
'px-4 h-[36px]': size === ButtonSizes.Small,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
(
|
||||
{
|
||||
children,
|
||||
className = '',
|
||||
variant = ButtonVariants.Primary,
|
||||
size = ButtonSizes.Small,
|
||||
color = ButtonColors.Primary,
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
ref={ref}
|
||||
className={`${getButtonClasses(size, variant, color)} ${className}`}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
},
|
||||
);
|
||||
25
apps/login/ui/CountUp.tsx
Normal file
25
apps/login/ui/CountUp.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
'use client';
|
||||
|
||||
import { useCountUp } from 'use-count-up';
|
||||
|
||||
const CountUp = ({
|
||||
start,
|
||||
end,
|
||||
duration = 1,
|
||||
}: {
|
||||
start: number;
|
||||
end: number;
|
||||
duration?: number;
|
||||
}) => {
|
||||
const { value } = useCountUp({
|
||||
isCounting: true,
|
||||
end,
|
||||
start,
|
||||
duration,
|
||||
decimalPlaces: 1,
|
||||
});
|
||||
|
||||
return <span>{value}</span>;
|
||||
};
|
||||
|
||||
export default CountUp;
|
||||
32
apps/login/ui/DefaultTags.tsx
Normal file
32
apps/login/ui/DefaultTags.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
// Default <head> tags we want shared across the app
|
||||
export function DefaultTags() {
|
||||
return (
|
||||
<>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link
|
||||
href="/favicon/apple-touch-icon.png"
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
/>
|
||||
<link
|
||||
href="/favicon/favicon-32x32.png"
|
||||
rel="icon"
|
||||
sizes="32x32"
|
||||
type="image/png"
|
||||
/>
|
||||
<link
|
||||
href="/favicon/favicon-16x16.png"
|
||||
rel="icon"
|
||||
sizes="16x16"
|
||||
type="image/png"
|
||||
/>
|
||||
<link href="/favicon/site.webmanifest" rel="manifest" />
|
||||
<link
|
||||
color="#000000"
|
||||
href="/favicon/safari-pinned-tab.svg"
|
||||
rel="mask-icon"
|
||||
/>
|
||||
<link href="/favicon/favicon.ico" rel="shortcut icon" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
20
apps/login/ui/ExternalLink.tsx
Normal file
20
apps/login/ui/ExternalLink.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { ArrowRightIcon } from '@heroicons/react/24/solid';
|
||||
|
||||
export const ExternalLink = ({
|
||||
children,
|
||||
href,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
href: string;
|
||||
}) => {
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
className="inline-flex space-x-2 rounded-lg bg-gray-700 px-3 py-1 text-sm font-medium text-gray-100 hover:bg-gray-500 hover:text-white"
|
||||
>
|
||||
<div>{children}</div>
|
||||
|
||||
<ArrowRightIcon className="block w-4" />
|
||||
</a>
|
||||
);
|
||||
};
|
||||
41
apps/login/ui/Footer.tsx
Normal file
41
apps/login/ui/Footer.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
'use client';
|
||||
|
||||
export default function Footer({
|
||||
reactVersion,
|
||||
nextVersion,
|
||||
}: {
|
||||
reactVersion: string;
|
||||
nextVersion: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="col-start-2 col-end-4 mt-28 flex items-center justify-between">
|
||||
<style jsx>
|
||||
{`
|
||||
.power-by {
|
||||
color: rgb(82 82 91);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
.power-by-text {
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
|
||||
<span className="power-by">
|
||||
<span className="power-by-text">Powered by</span>
|
||||
<svg height="20" viewBox="0 0 283 64" fill="none">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z"
|
||||
></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<div className="flex space-x-6 text-sm text-gray-600">
|
||||
<div>React: {reactVersion}</div>
|
||||
<div>Next: {nextVersion}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
101
apps/login/ui/GlobalNav.tsx
Normal file
101
apps/login/ui/GlobalNav.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
'use client';
|
||||
|
||||
import { demos, type Item } from '#/lib/demos';
|
||||
import '#/styles/globals.css';
|
||||
import { ZitadelLogo } from '#/ui/ZitadelLogo';
|
||||
import Link from 'next/link';
|
||||
import { useSelectedLayoutSegment } from 'next/navigation';
|
||||
import clsx from 'clsx';
|
||||
import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/solid';
|
||||
import { useState } from 'react';
|
||||
|
||||
export function GlobalNav() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const close = () => setIsOpen(false);
|
||||
|
||||
return (
|
||||
<div className="fixed top-0 z-10 flex w-full flex-col border-b border-gray-800 bg-background-dark-600 lg:bottom-0 lg:z-auto lg:w-72 lg:border-r lg:border-gray-800">
|
||||
<div className="flex h-14 items-center py-4 px-4 lg:h-auto">
|
||||
<Link
|
||||
href="/"
|
||||
className="group flex w-full items-center space-x-2.5"
|
||||
onClick={close}
|
||||
>
|
||||
<div className="h-8 w-8">
|
||||
<ZitadelLogo />
|
||||
</div>
|
||||
|
||||
<h2 className="font-medium tracking-wide text-gray-300 group-hover:text-gray-50">
|
||||
Login Playground <span className="Work in progress">(WIP)</span>
|
||||
</h2>
|
||||
</Link>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="group absolute right-0 top-0 flex h-14 items-center space-x-2 px-4 lg:hidden"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
>
|
||||
<div className="font-medium text-gray-100 group-hover:text-gray-400">
|
||||
Menu
|
||||
</div>
|
||||
{isOpen ? (
|
||||
<XMarkIcon className="block w-6 text-gray-300" />
|
||||
) : (
|
||||
<Bars3Icon className="block w-6 text-gray-300" />
|
||||
)}
|
||||
</button>
|
||||
|
||||
<div
|
||||
className={clsx('overflow-y-auto lg:static lg:block', {
|
||||
'fixed inset-x-0 bottom-0 top-14 mt-px bg-black': isOpen,
|
||||
hidden: !isOpen,
|
||||
})}
|
||||
>
|
||||
<nav className="space-y-6 px-2 py-5">
|
||||
{demos.map((section) => {
|
||||
return (
|
||||
<div key={section.name}>
|
||||
<div className="mb-2 px-3 text-xs font-semibold uppercase tracking-wider text-gray-600">
|
||||
<div>{section.name}</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
{section.items.map((item) => (
|
||||
<GlobalNavItem key={item.slug} item={item} close={close} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function GlobalNavItem({
|
||||
item,
|
||||
close,
|
||||
}: {
|
||||
item: Item;
|
||||
close: () => false | void;
|
||||
}) {
|
||||
const segment = useSelectedLayoutSegment();
|
||||
const isActive = item.slug === segment;
|
||||
|
||||
return (
|
||||
<Link
|
||||
onClick={close}
|
||||
href={`/${item.slug}`}
|
||||
className={clsx(
|
||||
'block rounded-md px-3 py-2 text-sm font-medium hover:text-gray-300',
|
||||
{
|
||||
'text-gray-500 hover:bg-gray-800': !isActive,
|
||||
'text-gray-200': isActive,
|
||||
},
|
||||
)}
|
||||
>
|
||||
{item.name}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
43
apps/login/ui/Header.tsx
Normal file
43
apps/login/ui/Header.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
'use client';
|
||||
|
||||
import styled from 'styled-components';
|
||||
|
||||
const HeadContainer = styled.header`
|
||||
position: relative;
|
||||
height: 64px;
|
||||
align-items: center;
|
||||
padding: 0px 8px;
|
||||
margin-bottom: 48px;
|
||||
display: flex;
|
||||
border: 0 solid #e5e7eb;
|
||||
color: rgb(244 244 245);
|
||||
grid-column-start: 2;
|
||||
grid-column-end: 4;
|
||||
`;
|
||||
|
||||
const Title = styled.span`
|
||||
margin: 0 8px;
|
||||
`;
|
||||
|
||||
const NextJsLogo = (props: any) => (
|
||||
<svg
|
||||
version="1.1"
|
||||
viewBox="0 0 148 90"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M34.992 23.495h27.855v2.219H37.546v16.699h23.792v2.219H37.546v18.334h25.591v2.219H34.992v-41.69zm30.35 0h2.96l13.115 18.334 13.405-18.334L113.055.207 83.1 43.756l15.436 21.429H95.46L81.417 45.683 67.316 65.185h-3.018L79.85 43.756 65.343 23.495zm34.297 2.219v-2.219h31.742v2.219h-14.623v39.47h-2.554v-39.47H99.64zM.145 23.495h3.192l44.011 66.003L29.16 65.185 2.814 26.648l-.116 38.537H.145v-41.69zm130.98 38.801c-.523 0-.914-.405-.914-.928 0-.524.391-.929.913-.929.528 0 .913.405.913.929 0 .523-.385.928-.913.928zm2.508-2.443H135c.019.742.56 1.24 1.354 1.24.888 0 1.391-.535 1.391-1.539v-6.356h1.391v6.362c0 1.808-1.043 2.849-2.77 2.849-1.62 0-2.732-1.01-2.732-2.556zm7.322-.08h1.379c.118.853.95 1.395 2.149 1.395 1.117 0 1.937-.58 1.937-1.377 0-.685-.521-1.097-1.708-1.377l-1.155-.28c-1.62-.38-2.36-1.166-2.36-2.487 0-1.602 1.304-2.668 3.26-2.668 1.82 0 3.15 1.066 3.23 2.58h-1.354c-.13-.828-.85-1.346-1.894-1.346-1.1 0-1.832.53-1.832 1.34 0 .642.472 1.01 1.64 1.284l.987.243c1.838.43 2.596 1.178 2.596 2.53 0 1.72-1.33 2.799-3.453 2.799-1.987 0-3.323-1.029-3.422-2.637z"
|
||||
fillRule="nonzero"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default function Header() {
|
||||
return (
|
||||
<HeadContainer>
|
||||
<NextJsLogo height={40} fill={`rgb(244 244 245)`} />
|
||||
<Title>The React Framework</Title>
|
||||
</HeadContainer>
|
||||
);
|
||||
}
|
||||
92
apps/login/ui/Input.tsx
Normal file
92
apps/login/ui/Input.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
'use client';
|
||||
import { CheckCircleIcon } from '@heroicons/react/24/solid';
|
||||
import clsx from 'clsx';
|
||||
import React, {
|
||||
ChangeEvent,
|
||||
DetailedHTMLProps,
|
||||
forwardRef,
|
||||
InputHTMLAttributes,
|
||||
ReactNode,
|
||||
} from 'react';
|
||||
|
||||
export type TextInputProps = DetailedHTMLProps<
|
||||
InputHTMLAttributes<HTMLInputElement>,
|
||||
HTMLInputElement
|
||||
> & {
|
||||
label: string;
|
||||
placeholder?: string;
|
||||
defaultValue?: string;
|
||||
error?: string | ReactNode;
|
||||
success?: string | ReactNode;
|
||||
disabled?: boolean;
|
||||
onChange?: (value: ChangeEvent<HTMLInputElement>) => void;
|
||||
onBlur?: (value: ChangeEvent<HTMLInputElement>) => void;
|
||||
};
|
||||
|
||||
const styles = (error: boolean, disabled: boolean) =>
|
||||
clsx({
|
||||
'h-40px mb-2px rounded p-2 bg-input-light-background dark:bg-input-dark-background transition-colors duration-300 grow':
|
||||
true,
|
||||
'border border-input-light-border dark:border-input-dark-border hover:border-black hover:dark:border-white focus:border-primary-light-500 focus:dark:border-primary-dark-500':
|
||||
true,
|
||||
'focus:outline-none focus:ring-0 text-base text-black dark:text-white placeholder:italic placeholder-gray-700 dark:placeholder-gray-700':
|
||||
true,
|
||||
'border border-warn-light-500 dark:border-warn-dark-500 hover:border-warn-light-500 hover:dark:border-warn-dark-500 focus:border-warn-light-500 focus:dark:border-warn-dark-500':
|
||||
error,
|
||||
'pointer-events-none text-gray-500 dark:text-gray-800 border border-gray-700 dark:border-gray-900 border-opacity-30 dark:border-opacity-30 hover:border-gray-700 hover:dark:border-gray-900 hover:border-opacity-30 hover:dark:border-opacity-30 cursor-default':
|
||||
disabled,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
export const TextInput = forwardRef<HTMLInputElement, TextInputProps>(
|
||||
(
|
||||
{
|
||||
label,
|
||||
placeholder,
|
||||
defaultValue,
|
||||
required = false,
|
||||
error,
|
||||
disabled,
|
||||
success,
|
||||
onChange,
|
||||
onBlur,
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
return (
|
||||
<label className="flex flex-col text-12px text-input-light-label dark:text-input-dark-label">
|
||||
<span
|
||||
className={`leading-14.5px mb-1 ${
|
||||
error ? 'text-warn-light-500 dark:text-warn-dark-500' : ''
|
||||
}`}
|
||||
>
|
||||
{label} {required && '*'}
|
||||
</span>
|
||||
<input
|
||||
ref={ref}
|
||||
className={styles(!!error, !!disabled)}
|
||||
defaultValue={defaultValue}
|
||||
required={required}
|
||||
disabled={disabled}
|
||||
placeholder={placeholder}
|
||||
autoComplete={props.autoComplete ?? 'off'}
|
||||
onChange={(e) => onChange && onChange(e)}
|
||||
onBlur={(e) => onBlur && onBlur(e)}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
<div className="leading-14.5px h-14.5px text-warn-light-500 dark:text-warn-dark-500 flex flex-row items-center text-12px">
|
||||
<span>{error ? error : ' '}</span>
|
||||
</div>
|
||||
|
||||
{success && (
|
||||
<div className="text-md mt-1 flex flex-row items-center text-green-500">
|
||||
<CheckCircleIcon className="h-4 w-4" />
|
||||
<span className="ml-1">{success}</span>
|
||||
</div>
|
||||
)}
|
||||
</label>
|
||||
);
|
||||
},
|
||||
);
|
||||
64
apps/login/ui/MobileNavToggle.tsx
Normal file
64
apps/login/ui/MobileNavToggle.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
'use client';
|
||||
|
||||
import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/solid';
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
|
||||
const MobileNavContext = React.createContext<
|
||||
[boolean, React.Dispatch<React.SetStateAction<boolean>>] | undefined
|
||||
>(undefined);
|
||||
|
||||
export function MobileNavContextProvider({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
return (
|
||||
<MobileNavContext.Provider value={[isOpen, setIsOpen]}>
|
||||
{children}
|
||||
</MobileNavContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useMobileNavToggle() {
|
||||
const context = React.useContext(MobileNavContext);
|
||||
if (context === undefined) {
|
||||
throw new Error(
|
||||
'useMobileNavToggle must be used within a MobileNavContextProvider',
|
||||
);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
export function MobileNavToggle({ children }: { children: React.ReactNode }) {
|
||||
const [isOpen, setIsOpen] = useMobileNavToggle();
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
className="group absolute right-0 top-0 flex h-14 items-center space-x-2 px-4 lg:hidden"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
>
|
||||
<div className="font-medium text-gray-100 group-hover:text-gray-400">
|
||||
Menu
|
||||
</div>
|
||||
{isOpen ? (
|
||||
<XMarkIcon className="block w-6 text-gray-300" />
|
||||
) : (
|
||||
<Bars3Icon className="block w-6 text-gray-300" />
|
||||
)}
|
||||
</button>
|
||||
|
||||
<div
|
||||
className={clsx('overflow-y-auto lg:static lg:block', {
|
||||
'fixed inset-x-0 bottom-0 top-14 bg-gray-900': isOpen,
|
||||
hidden: !isOpen,
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
102
apps/login/ui/PasswordComplexityPolicy.tsx
Normal file
102
apps/login/ui/PasswordComplexityPolicy.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import {
|
||||
lowerCaseValidator,
|
||||
numberValidator,
|
||||
symbolValidator,
|
||||
upperCaseValidator,
|
||||
} from '../utils/validators';
|
||||
import { ClientError } from 'nice-grpc';
|
||||
|
||||
const fetcher = (url: string) =>
|
||||
fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.ok) {
|
||||
return res.json();
|
||||
} else {
|
||||
return res.json().then((error) => {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
})
|
||||
.then((resp) => resp.policy);
|
||||
|
||||
type Props = {
|
||||
password: string;
|
||||
equals: boolean;
|
||||
isValid: (valid: boolean) => void;
|
||||
isMe?: boolean;
|
||||
userId?: string;
|
||||
};
|
||||
|
||||
const check = (
|
||||
<i className="las la-check text-state-success-light-color dark:text-state-success-dark-color mr-4 text-lg"></i>
|
||||
);
|
||||
const cross = (
|
||||
<i className="las la-times text-warn-light-500 dark:text-warn-dark-500 mr-4 text-lg"></i>
|
||||
);
|
||||
const desc =
|
||||
'text-14px leading-4 text-input-light-label dark:text-input-dark-label';
|
||||
|
||||
export default function PasswordComplexityPolicy({
|
||||
password,
|
||||
equals,
|
||||
isValid,
|
||||
isMe,
|
||||
userId,
|
||||
}: Props) {
|
||||
// const { data: policy } = useSWR<Policy, ClientError>(
|
||||
// `/api/user/passwordpolicy/${isMe ? 'me' : userId}`,
|
||||
// fetcher,
|
||||
// );
|
||||
// if (policy) {
|
||||
// const hasMinLength = password?.length >= policy.minLength;
|
||||
// const hasSymbol = symbolValidator(password);
|
||||
// const hasNumber = numberValidator(password);
|
||||
// const hasUppercase = upperCaseValidator(password);
|
||||
// const hasLowercase = lowerCaseValidator(password);
|
||||
|
||||
// const policyIsValid =
|
||||
// (policy.hasLowercase ? hasLowercase : true) &&
|
||||
// (policy.hasNumber ? hasNumber : true) &&
|
||||
// (policy.hasUppercase ? hasUppercase : true) &&
|
||||
// (policy.hasSymbol ? hasSymbol : true) &&
|
||||
// hasMinLength;
|
||||
|
||||
// isValid(policyIsValid);
|
||||
|
||||
// return (
|
||||
// <div className="mb-4 grid grid-cols-2 gap-x-8 gap-y-2">
|
||||
// <div className="flex flex-row items-center">
|
||||
// {hasMinLength ? check : cross}
|
||||
// <span className={desc}>Password length {policy.minLength}</span>
|
||||
// </div>
|
||||
// <div className="flex flex-row items-center">
|
||||
// {hasSymbol ? check : cross}
|
||||
// <span className={desc}>has Symbol</span>
|
||||
// </div>
|
||||
// <div className="flex flex-row items-center">
|
||||
// {hasNumber ? check : cross}
|
||||
// <span className={desc}>has Number</span>
|
||||
// </div>
|
||||
// <div className="flex flex-row items-center">
|
||||
// {hasUppercase ? check : cross}
|
||||
// <span className={desc}>has uppercase</span>
|
||||
// </div>
|
||||
// <div className="flex flex-row items-center">
|
||||
// {hasLowercase ? check : cross}
|
||||
// <span className={desc}>has lowercase</span>
|
||||
// </div>
|
||||
// <div className="flex flex-row items-center">
|
||||
// {equals ? check : cross}
|
||||
// <span className={desc}>equals</span>
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
// } else {
|
||||
return null;
|
||||
// }
|
||||
}
|
||||
33
apps/login/ui/RootStyleRegistry.tsx
Normal file
33
apps/login/ui/RootStyleRegistry.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { useServerInsertedHTML } from 'next/navigation';
|
||||
import {
|
||||
useStyledComponentsRegistry,
|
||||
useStyledJsxRegistry,
|
||||
} from '#/lib/styling';
|
||||
|
||||
export default function RootStyleRegistry({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const [StyledComponentsRegistry, styledComponentsFlushEffect] =
|
||||
useStyledComponentsRegistry();
|
||||
const [StyledJsxRegistry, styledJsxFlushEffect] = useStyledJsxRegistry();
|
||||
|
||||
useServerInsertedHTML(() => {
|
||||
return (
|
||||
<>
|
||||
{styledJsxFlushEffect()}
|
||||
{styledComponentsFlushEffect()}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<StyledComponentsRegistry>
|
||||
<StyledJsxRegistry>{children}</StyledJsxRegistry>
|
||||
</StyledComponentsRegistry>
|
||||
);
|
||||
}
|
||||
16
apps/login/ui/SkeletonCard.tsx
Normal file
16
apps/login/ui/SkeletonCard.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import clsx from 'clsx';
|
||||
|
||||
export const SkeletonCard = ({ isLoading }: { isLoading?: boolean }) => (
|
||||
<div
|
||||
className={clsx('rounded-2xl bg-gray-900/80 p-4', {
|
||||
'relative overflow-hidden before:absolute before:inset-0 before:-translate-x-full before:animate-[shimmer_1.5s_infinite] before:bg-gradient-to-r before:from-transparent before:via-white/10 before:to-transparent':
|
||||
isLoading,
|
||||
})}
|
||||
>
|
||||
<div className="space-y-3">
|
||||
<div className="h-14 rounded-lg bg-gray-700" />
|
||||
<div className="h-3 w-11/12 rounded-lg bg-gray-700" />
|
||||
<div className="h-3 w-8/12 rounded-lg bg-gray-700" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
35
apps/login/ui/Tab.tsx
Normal file
35
apps/login/ui/Tab.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
'use client';
|
||||
|
||||
import type { Item } from '#/ui/TabGroup';
|
||||
import clsx from 'clsx';
|
||||
import Link from 'next/link';
|
||||
import { useSelectedLayoutSegment } from 'next/navigation';
|
||||
|
||||
export const Tab = ({
|
||||
path,
|
||||
item: { slug, text },
|
||||
}: {
|
||||
path: string;
|
||||
item: Item;
|
||||
}) => {
|
||||
const segment = useSelectedLayoutSegment();
|
||||
const href = slug ? path + '/' + slug : path;
|
||||
const isActive =
|
||||
// Example home pages e.g. `/layouts`
|
||||
(!slug && segment === null) ||
|
||||
// Nested pages e.g. `/layouts/electronics`
|
||||
segment === slug;
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={href}
|
||||
className={clsx('mt-2 mr-2 rounded-lg px-3 py-1 text-sm font-medium', {
|
||||
'bg-gray-700 text-gray-100 hover:bg-gray-500 hover:text-white':
|
||||
!isActive,
|
||||
'bg-vercel-blue text-white': isActive,
|
||||
})}
|
||||
>
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
16
apps/login/ui/TabGroup.tsx
Normal file
16
apps/login/ui/TabGroup.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Tab } from '#/ui/Tab';
|
||||
|
||||
export type Item = {
|
||||
text: string;
|
||||
slug?: string;
|
||||
};
|
||||
|
||||
export const TabGroup = ({ path, items }: { path: string; items: Item[] }) => {
|
||||
return (
|
||||
<div className="-mt-2 flex flex-wrap items-center">
|
||||
{items.map((item) => (
|
||||
<Tab key={path + item.slug} item={item} path={path} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
11
apps/login/ui/VercelLogo.tsx
Normal file
11
apps/login/ui/VercelLogo.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
export function VercelLogo() {
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 4438 1000"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M2223.75 250C2051.25 250 1926.87 362.5 1926.87 531.25C1926.87 700 2066.72 812.5 2239.38 812.5C2343.59 812.5 2435.47 771.25 2492.34 701.719L2372.81 632.656C2341.25 667.188 2293.28 687.344 2239.38 687.344C2164.53 687.344 2100.94 648.281 2077.34 585.781H2515.16C2518.59 568.281 2520.63 550.156 2520.63 531.094C2520.63 362.5 2396.41 250 2223.75 250ZM2076.09 476.562C2095.62 414.219 2149.06 375 2223.75 375C2298.59 375 2352.03 414.219 2371.41 476.562H2076.09ZM2040.78 78.125L1607.81 828.125L1174.69 78.125H1337.03L1607.66 546.875L1878.28 78.125H2040.78ZM577.344 0L1154.69 1000H0L577.344 0ZM3148.75 531.25C3148.75 625 3210 687.5 3305 687.5C3369.38 687.5 3417.66 658.281 3442.5 610.625L3562.5 679.844C3512.81 762.656 3419.69 812.5 3305 812.5C3132.34 812.5 3008.13 700 3008.13 531.25C3008.13 362.5 3132.5 250 3305 250C3419.69 250 3512.66 299.844 3562.5 382.656L3442.5 451.875C3417.66 404.219 3369.38 375 3305 375C3210.16 375 3148.75 437.5 3148.75 531.25ZM4437.5 78.125V796.875H4296.88V78.125H4437.5ZM3906.25 250C3733.75 250 3609.38 362.5 3609.38 531.25C3609.38 700 3749.38 812.5 3921.88 812.5C4026.09 812.5 4117.97 771.25 4174.84 701.719L4055.31 632.656C4023.75 667.188 3975.78 687.344 3921.88 687.344C3847.03 687.344 3783.44 648.281 3759.84 585.781H4197.66C4201.09 568.281 4203.12 550.156 4203.12 531.094C4203.12 362.5 4078.91 250 3906.25 250ZM3758.59 476.562C3778.13 414.219 3831.41 375 3906.25 375C3981.09 375 4034.53 414.219 4053.91 476.562H3758.59ZM2961.25 265.625V417.031C2945.63 412.5 2929.06 409.375 2911.25 409.375C2820.47 409.375 2755 471.875 2755 565.625V796.875H2614.38V265.625H2755V409.375C2755 330 2847.34 265.625 2961.25 265.625Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
15
apps/login/ui/ZitadelLogo.tsx
Normal file
15
apps/login/ui/ZitadelLogo.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { ZitadelLogoDark } from './ZitadelLogoDark';
|
||||
import { ZitadelLogoLight } from './ZitadelLogoLight';
|
||||
|
||||
export function ZitadelLogo() {
|
||||
return (
|
||||
<>
|
||||
<div className="hidden dark:flex">
|
||||
<ZitadelLogoLight />
|
||||
</div>
|
||||
<div className="flex dark:hidden">
|
||||
<ZitadelLogoDark />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
210
apps/login/ui/ZitadelLogoDark.tsx
Normal file
210
apps/login/ui/ZitadelLogoDark.tsx
Normal file
@@ -0,0 +1,210 @@
|
||||
import { FC } from 'react';
|
||||
|
||||
export const ZitadelLogoDark: FC = (props) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fillRule="evenodd"
|
||||
strokeLinejoin="round"
|
||||
strokeMiterlimit="2"
|
||||
height="100%"
|
||||
width="100%"
|
||||
clipRule="evenodd"
|
||||
viewBox="0 0 467 467"
|
||||
>
|
||||
<g transform="matrix(.56485 0 0 .65932 -1282.85 0)">
|
||||
<path
|
||||
fill="none"
|
||||
d="M2271.15 0H3097.9230000000002V708.241H2271.15z"
|
||||
></path>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M1493.5 1056.38V1037h3v24.62l-70.48-41.24 70.48-40.988V1004h-3v-19.392l-61.52 35.782 61.52 35.99z"
|
||||
transform="matrix(4.96737 -1.14029 1.331 4.25561 -5923.46 -2258.26)"
|
||||
></path>
|
||||
<path
|
||||
fill="url(#_Linear1)"
|
||||
d="M212.517 110h-12.125L190 92l-10.392 18h-12.125L190 71l22.517 39z"
|
||||
transform="matrix(31.0036 0 0 15.0393 -397275 -666.457) matrix(-.04293 -.28297 .16022 -.07582 12884.5 137.392)"
|
||||
></path>
|
||||
<path
|
||||
fill="url(#_Linear2)"
|
||||
d="M212.517 110h-12.125L190 92l-10.392 18h-12.125L190 71l22.517 39z"
|
||||
transform="matrix(31.0036 0 0 15.0393 -397275 -666.457) matrix(.16022 .07582 -.04293 .28297 12878.9 10.875)"
|
||||
></path>
|
||||
<path
|
||||
fill="url(#_Linear3)"
|
||||
d="M212.517 110h-12.125L190 92l-10.392 18h-12.125L190 71l22.517 39z"
|
||||
transform="matrix(31.0036 0 0 15.0393 -397275 -666.457) matrix(-.11729 .20715 -.11729 -.20715 12943.8 65.7)"
|
||||
></path>
|
||||
<path
|
||||
fill="url(#_Linear4)"
|
||||
d="M139.622 117L149 142h-18.756l9.378-25z"
|
||||
transform="matrix(31.0036 0 0 15.0393 -397275 -666.457) matrix(-.16022 -.07582 .04293 -.28297 12917.4 132.195)"
|
||||
></path>
|
||||
<path
|
||||
fill="url(#_Linear5)"
|
||||
d="M139.622 117L149 142h-18.756l9.378-25z"
|
||||
transform="matrix(31.0036 0 0 15.0393 -397275 -666.457) matrix(-.11729 .20715 .11729 .20715 12897.8 5.875)"
|
||||
></path>
|
||||
<path
|
||||
fill="url(#_Linear6)"
|
||||
d="M139.622 117L149 142h-18.756l9.378-25z"
|
||||
transform="matrix(31.0036 0 0 15.0393 -397275 -666.457) matrix(-.04293 -.28297 -.16022 .07582 12936.8 97.644)"
|
||||
></path>
|
||||
<circle
|
||||
cx="1496"
|
||||
cy="1004"
|
||||
r="7"
|
||||
fill="#fff"
|
||||
transform="matrix(4.96737 -1.14029 1.331 4.25561 -5928.43 -2257.12)"
|
||||
></circle>
|
||||
<circle
|
||||
cx="1496"
|
||||
cy="1004"
|
||||
r="7"
|
||||
fill="#fff"
|
||||
transform="matrix(4.96737 -1.14029 1.331 4.25561 -5884.5 -2116.69)"
|
||||
></circle>
|
||||
<circle
|
||||
cx="1496"
|
||||
cy="1004"
|
||||
r="7"
|
||||
fill="#fff"
|
||||
transform="matrix(4.96737 -1.14029 1.331 4.25561 -5855.22 -2023.06)"
|
||||
></circle>
|
||||
<circle
|
||||
cx="1496"
|
||||
cy="1004"
|
||||
r="7"
|
||||
fill="#fff"
|
||||
transform="matrix(4.96737 -1.14029 1.331 4.25561 -6234.47 -2112.14)"
|
||||
></circle>
|
||||
<circle
|
||||
cx="1496"
|
||||
cy="1004"
|
||||
r="7"
|
||||
fill="#fff"
|
||||
transform="matrix(4.96737 -1.14029 1.331 4.25561 -5957.71 -2350.75)"
|
||||
></circle>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M1499.26 757.787s-1.89-1.298-2.26-2.587c-.29-1.018-.43-4.538-.46-5.2-.13-2.697 2.67-4.356 2.67-4.356l-9.2.191s3.14-.122 3.45 4.165c.05.661-.23 3.476-.46 5.2-.09 1.247-1.8 2.468-1.8 2.468l8.06.119z"
|
||||
transform="matrix(4.96737 -1.14029 1.16463 3.72366 -5477.99 -831.33)"
|
||||
></path>
|
||||
<path
|
||||
fill="none"
|
||||
d="M1495 760v-16"
|
||||
transform="matrix(4.96737 -1.14029 1.16463 3.72366 -5404.79 -597.271)"
|
||||
></path>
|
||||
<g>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M1498.27 757.077s-1.56-.617-1.62-2.277c0-1.142-.01-1.519 0-2.784-.03-.682-.06-1.408 0-2.067.13-3.113 1.85-3.793 1.85-3.793l-7.04-.225s1.91.788 2.19 3.899c.06.659.04 1.698 0 2.379a88.86 88.86 0 000 2.309c.03 1.816-1.07 2.309-1.07 2.309l5.69.25z"
|
||||
transform="matrix(4.96737 -1.14029 1.16463 3.72366 -5404.79 -597.271)"
|
||||
></path>
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
fill="none"
|
||||
d="M1496.17 759.473l59.37-39.459"
|
||||
transform="matrix(4.96737 -1.14029 1.16463 3.72366 -5770.62 -677.495)"
|
||||
></path>
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M1500.86 762.056s-1-1.656 2.23-4.6c1.82-1.659 4.24-3.305 6.89-5.201 4.84-3.465 10.7-7.315 16.54-11.206 4.93-3.283 9.86-6.57 14.3-9.369 3.7-2.331 7.03-4.384 9.72-5.88.53-.294 1.06-.471 1.51-.771 2.68-1.772 4.8-.061 4.8-.061l-4.62-8.686s-.24 3.172-2.23 4.715c-.43.336-.85.744-1.33 1.123-2.47 1.933-5.68 4.224-9.28 6.747-4.33 3.031-9.26 6.299-14.2 9.571-5.84 3.876-11.67 7.796-16.7 10.891-2.75 1.694-5.21 3.248-7.36 4.269-3.14 1.488-5.85.019-5.85.019l5.58 8.439z"
|
||||
transform="matrix(4.96737 -1.14029 1.16463 3.72366 -5770.62 -677.495)"
|
||||
></path>
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
fill="none"
|
||||
d="M1496.17 759.473l59.37-39.459"
|
||||
transform="matrix(4.96737 -1.14029 -1.16463 -3.72366 -3997 4993.28)"
|
||||
></path>
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M1496.1 754.362s1.1 1.245 5.03-.764c2.12-1.089 4.61-2.575 7.36-4.269 5.03-3.095 10.86-7.015 16.7-10.891 4.94-3.272 9.75-6.606 14.08-9.636 3.6-2.523 10.09-6.743 10.54-7.052 2.94-2.02 2.37-3.554 2.37-3.554l3.1 5.956s-1.51-1.247-3.91.529c-.44.325-6.85 4.668-10.55 6.999-4.44 2.799-9.37 6.086-14.3 9.369-5.84 3.891-11.7 7.741-16.54 11.206-2.65 1.896-5.09 3.516-6.89 5.201-3.62 3.385-1.83 5.827-1.83 5.827l-5.16-8.921z"
|
||||
transform="matrix(4.96737 -1.14029 -1.16463 -3.72366 -3997 4993.28)"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="_Linear1"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
gradientTransform="scale(-160.7235) rotate(-75 -.938 .578)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stopColor="#FF8F00"></stop>
|
||||
<stop offset="1" stopColor="#FE00FF"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="_Linear2"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
gradientTransform="scale(160.7235) rotate(-15 4.962 -1.993)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stopColor="#FF8F00"></stop>
|
||||
<stop offset="1" stopColor="#FE00FF"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="_Linear3"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
gradientTransform="rotate(-135 173.811 54.311) scale(160.724)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stopColor="#FF8F00"></stop>
|
||||
<stop offset="1" stopColor="#FE00FF"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="_Linear4"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
gradientTransform="scale(-160.7235) rotate(-15 -4.103 4.77)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stopColor="#FF8F00"></stop>
|
||||
<stop offset="1" stopColor="#FE00FF"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="_Linear5"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
gradientTransform="scale(-160.724 160.724) rotate(45 -1.58 -1.166)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stopColor="#FF8F00"></stop>
|
||||
<stop offset="1" stopColor="#FE00FF"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="_Linear6"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
gradientTransform="scale(-160.7235 160.7235) rotate(-75 .592 1.434)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stopColor="#FF8F00"></stop>
|
||||
<stop offset="1" stopColor="#FE00FF"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
210
apps/login/ui/ZitadelLogoLight.tsx
Normal file
210
apps/login/ui/ZitadelLogoLight.tsx
Normal file
@@ -0,0 +1,210 @@
|
||||
import { FC } from 'react';
|
||||
|
||||
export const ZitadelLogoLight: FC = (props) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fillRule="evenodd"
|
||||
strokeLinejoin="round"
|
||||
strokeMiterlimit="2"
|
||||
height="100%"
|
||||
width="100%"
|
||||
clipRule="evenodd"
|
||||
viewBox="0 0 467 467"
|
||||
>
|
||||
<g transform="matrix(.56485 0 0 .65932 -1282.85 0)">
|
||||
<path
|
||||
fill="none"
|
||||
d="M2271.15 0H3097.9230000000002V708.241H2271.15z"
|
||||
></path>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M1493.5 1056.38V1037h3v24.62l-70.48-41.24 70.48-40.988V1004h-3v-19.392l-61.52 35.782 61.52 35.99z"
|
||||
transform="matrix(4.96737 -1.14029 1.331 4.25561 -5923.46 -2258.26)"
|
||||
></path>
|
||||
<path
|
||||
fill="url(#_Linear1)"
|
||||
d="M212.517 110h-12.125L190 92l-10.392 18h-12.125L190 71l22.517 39z"
|
||||
transform="matrix(31.0036 0 0 15.0393 -397275 -666.457) matrix(-.04293 -.28297 .16022 -.07582 12884.5 137.392)"
|
||||
></path>
|
||||
<path
|
||||
fill="url(#_Linear2)"
|
||||
d="M212.517 110h-12.125L190 92l-10.392 18h-12.125L190 71l22.517 39z"
|
||||
transform="matrix(31.0036 0 0 15.0393 -397275 -666.457) matrix(.16022 .07582 -.04293 .28297 12878.9 10.875)"
|
||||
></path>
|
||||
<path
|
||||
fill="url(#_Linear3)"
|
||||
d="M212.517 110h-12.125L190 92l-10.392 18h-12.125L190 71l22.517 39z"
|
||||
transform="matrix(31.0036 0 0 15.0393 -397275 -666.457) matrix(-.11729 .20715 -.11729 -.20715 12943.8 65.7)"
|
||||
></path>
|
||||
<path
|
||||
fill="url(#_Linear4)"
|
||||
d="M139.622 117L149 142h-18.756l9.378-25z"
|
||||
transform="matrix(31.0036 0 0 15.0393 -397275 -666.457) matrix(-.16022 -.07582 .04293 -.28297 12917.4 132.195)"
|
||||
></path>
|
||||
<path
|
||||
fill="url(#_Linear5)"
|
||||
d="M139.622 117L149 142h-18.756l9.378-25z"
|
||||
transform="matrix(31.0036 0 0 15.0393 -397275 -666.457) matrix(-.11729 .20715 .11729 .20715 12897.8 5.875)"
|
||||
></path>
|
||||
<path
|
||||
fill="url(#_Linear6)"
|
||||
d="M139.622 117L149 142h-18.756l9.378-25z"
|
||||
transform="matrix(31.0036 0 0 15.0393 -397275 -666.457) matrix(-.04293 -.28297 -.16022 .07582 12936.8 97.644)"
|
||||
></path>
|
||||
<circle
|
||||
cx="1496"
|
||||
cy="1004"
|
||||
r="7"
|
||||
fill="#fff"
|
||||
transform="matrix(4.96737 -1.14029 1.331 4.25561 -5928.43 -2257.12)"
|
||||
></circle>
|
||||
<circle
|
||||
cx="1496"
|
||||
cy="1004"
|
||||
r="7"
|
||||
fill="#fff"
|
||||
transform="matrix(4.96737 -1.14029 1.331 4.25561 -5884.5 -2116.69)"
|
||||
></circle>
|
||||
<circle
|
||||
cx="1496"
|
||||
cy="1004"
|
||||
r="7"
|
||||
fill="#fff"
|
||||
transform="matrix(4.96737 -1.14029 1.331 4.25561 -5855.22 -2023.06)"
|
||||
></circle>
|
||||
<circle
|
||||
cx="1496"
|
||||
cy="1004"
|
||||
r="7"
|
||||
fill="#fff"
|
||||
transform="matrix(4.96737 -1.14029 1.331 4.25561 -6234.47 -2112.14)"
|
||||
></circle>
|
||||
<circle
|
||||
cx="1496"
|
||||
cy="1004"
|
||||
r="7"
|
||||
fill="#fff"
|
||||
transform="matrix(4.96737 -1.14029 1.331 4.25561 -5957.71 -2350.75)"
|
||||
></circle>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M1499.26 757.787s-1.89-1.298-2.26-2.587c-.29-1.018-.43-4.538-.46-5.2-.13-2.697 2.67-4.356 2.67-4.356l-9.2.191s3.14-.122 3.45 4.165c.05.661-.23 3.476-.46 5.2-.09 1.247-1.8 2.468-1.8 2.468l8.06.119z"
|
||||
transform="matrix(4.96737 -1.14029 1.16463 3.72366 -5477.99 -831.33)"
|
||||
></path>
|
||||
<path
|
||||
fill="none"
|
||||
d="M1495 760v-16"
|
||||
transform="matrix(4.96737 -1.14029 1.16463 3.72366 -5404.79 -597.271)"
|
||||
></path>
|
||||
<g>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M1498.27 757.077s-1.56-.617-1.62-2.277c0-1.142-.01-1.519 0-2.784-.03-.682-.06-1.408 0-2.067.13-3.113 1.85-3.793 1.85-3.793l-7.04-.225s1.91.788 2.19 3.899c.06.659.04 1.698 0 2.379a88.86 88.86 0 000 2.309c.03 1.816-1.07 2.309-1.07 2.309l5.69.25z"
|
||||
transform="matrix(4.96737 -1.14029 1.16463 3.72366 -5404.79 -597.271)"
|
||||
></path>
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
fill="none"
|
||||
d="M1496.17 759.473l59.37-39.459"
|
||||
transform="matrix(4.96737 -1.14029 1.16463 3.72366 -5770.62 -677.495)"
|
||||
></path>
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M1500.86 762.056s-1-1.656 2.23-4.6c1.82-1.659 4.24-3.305 6.89-5.201 4.84-3.465 10.7-7.315 16.54-11.206 4.93-3.283 9.86-6.57 14.3-9.369 3.7-2.331 7.03-4.384 9.72-5.88.53-.294 1.06-.471 1.51-.771 2.68-1.772 4.8-.061 4.8-.061l-4.62-8.686s-.24 3.172-2.23 4.715c-.43.336-.85.744-1.33 1.123-2.47 1.933-5.68 4.224-9.28 6.747-4.33 3.031-9.26 6.299-14.2 9.571-5.84 3.876-11.67 7.796-16.7 10.891-2.75 1.694-5.21 3.248-7.36 4.269-3.14 1.488-5.85.019-5.85.019l5.58 8.439z"
|
||||
transform="matrix(4.96737 -1.14029 1.16463 3.72366 -5770.62 -677.495)"
|
||||
></path>
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
fill="none"
|
||||
d="M1496.17 759.473l59.37-39.459"
|
||||
transform="matrix(4.96737 -1.14029 -1.16463 -3.72366 -3997 4993.28)"
|
||||
></path>
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M1496.1 754.362s1.1 1.245 5.03-.764c2.12-1.089 4.61-2.575 7.36-4.269 5.03-3.095 10.86-7.015 16.7-10.891 4.94-3.272 9.75-6.606 14.08-9.636 3.6-2.523 10.09-6.743 10.54-7.052 2.94-2.02 2.37-3.554 2.37-3.554l3.1 5.956s-1.51-1.247-3.91.529c-.44.325-6.85 4.668-10.55 6.999-4.44 2.799-9.37 6.086-14.3 9.369-5.84 3.891-11.7 7.741-16.54 11.206-2.65 1.896-5.09 3.516-6.89 5.201-3.62 3.385-1.83 5.827-1.83 5.827l-5.16-8.921z"
|
||||
transform="matrix(4.96737 -1.14029 -1.16463 -3.72366 -3997 4993.28)"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="_Linear1"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
gradientTransform="scale(-160.7235) rotate(-75 -.938 .578)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stopColor="#FF8F00"></stop>
|
||||
<stop offset="1" stopColor="#FE00FF"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="_Linear2"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
gradientTransform="scale(160.7235) rotate(-15 4.962 -1.993)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stopColor="#FF8F00"></stop>
|
||||
<stop offset="1" stopColor="#FE00FF"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="_Linear3"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
gradientTransform="rotate(-135 173.811 54.311) scale(160.724)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stopColor="#FF8F00"></stop>
|
||||
<stop offset="1" stopColor="#FE00FF"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="_Linear4"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
gradientTransform="scale(-160.7235) rotate(-15 -4.103 4.77)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stopColor="#FF8F00"></stop>
|
||||
<stop offset="1" stopColor="#FE00FF"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="_Linear5"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
gradientTransform="scale(-160.724 160.724) rotate(45 -1.58 -1.166)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stopColor="#FF8F00"></stop>
|
||||
<stop offset="1" stopColor="#FE00FF"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="_Linear6"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
gradientTransform="scale(-160.7235 160.7235) rotate(-75 .592 1.434)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stopColor="#FF8F00"></stop>
|
||||
<stop offset="1" stopColor="#FE00FF"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
Reference in New Issue
Block a user