Tailwind CSS 4 Migration (#100)
* Updated to TailwindCSS v4 * Moved CSS module to its own CSS file because of lightingcss strict validation * Respect next parameter in middleware * Updated all packages. * Split CSSs for better organization. * Redesigned theme and auth pages * Improved pill and header design * Formatted files using Prettier * Better footer layout * Better auth layout * Bump version of the repository to 2.0.0
This commit is contained in:
committed by
GitHub
parent
d799f54ede
commit
4e91f267e0
@@ -111,7 +111,12 @@ export function AccountSelector({
|
||||
<If
|
||||
condition={selected}
|
||||
fallback={
|
||||
<span className={'flex max-w-full items-center space-x-4'}>
|
||||
<span
|
||||
className={cn('flex max-w-full items-center', {
|
||||
'justify-center gap-x-0': collapsed,
|
||||
'gap-x-4': !collapsed,
|
||||
})}
|
||||
>
|
||||
<PersonalAccountAvatar />
|
||||
|
||||
<span
|
||||
@@ -125,12 +130,17 @@ export function AccountSelector({
|
||||
}
|
||||
>
|
||||
{(account) => (
|
||||
<span className={'flex max-w-full items-center space-x-4'}>
|
||||
<Avatar className={'h-6 w-6 rounded-sm'}>
|
||||
<span
|
||||
className={cn('flex max-w-full items-center', {
|
||||
'justify-center gap-x-0': collapsed,
|
||||
'gap-x-4': !collapsed,
|
||||
})}
|
||||
>
|
||||
<Avatar className={'rounded-xs h-6 w-6'}>
|
||||
<AvatarImage src={account.image ?? undefined} />
|
||||
|
||||
<AvatarFallback
|
||||
className={'group-hover:bg-background rounded-sm'}
|
||||
className={'group-hover:bg-background rounded-xs'}
|
||||
>
|
||||
{account.label ? account.label[0] : ''}
|
||||
</AvatarFallback>
|
||||
@@ -212,11 +222,11 @@ export function AccountSelector({
|
||||
}}
|
||||
>
|
||||
<div className={'flex items-center'}>
|
||||
<Avatar className={'mr-2 h-6 w-6 rounded-sm'}>
|
||||
<Avatar className={'rounded-xs mr-2 h-6 w-6'}>
|
||||
<AvatarImage src={account.image ?? undefined} />
|
||||
|
||||
<AvatarFallback
|
||||
className={cn('rounded-sm', {
|
||||
className={cn('rounded-xs', {
|
||||
['bg-background']: value === account.value,
|
||||
['group-hover:bg-background']:
|
||||
value !== account.value,
|
||||
@@ -276,7 +286,7 @@ export function AccountSelector({
|
||||
|
||||
function UserAvatar(props: { pictureUrl?: string }) {
|
||||
return (
|
||||
<Avatar className={'h-6 w-6 rounded-sm'}>
|
||||
<Avatar className={'rounded-xs h-6 w-6'}>
|
||||
<AvatarImage src={props.pictureUrl} />
|
||||
</Avatar>
|
||||
);
|
||||
|
||||
@@ -88,7 +88,7 @@ export function PersonalAccountDropdown({
|
||||
'animate-in fade-in focus:outline-primary flex cursor-pointer items-center duration-500 group-data-[minimized=true]:px-0',
|
||||
className ?? '',
|
||||
{
|
||||
['active:bg-secondary/50 items-center space-x-4 rounded-md' +
|
||||
['active:bg-secondary/50 items-center gap-4 rounded-md' +
|
||||
' hover:bg-secondary p-2 transition-colors']: showProfileName,
|
||||
},
|
||||
)}
|
||||
@@ -129,8 +129,8 @@ export function PersonalAccountDropdown({
|
||||
</If>
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent className={'xl:!min-w-[15rem]'}>
|
||||
<DropdownMenuItem className={'!h-10 rounded-none'}>
|
||||
<DropdownMenuContent className={'xl:min-w-[15rem]!'}>
|
||||
<DropdownMenuItem className={'h-10! rounded-none'}>
|
||||
<div
|
||||
className={'flex flex-col justify-start truncate text-left text-xs'}
|
||||
>
|
||||
|
||||
@@ -70,8 +70,8 @@ async function PersonalAccountPage(props: { account: Account }) {
|
||||
/>
|
||||
|
||||
<div className={'flex items-center justify-between'}>
|
||||
<div className={'flex items-center space-x-4'}>
|
||||
<div className={'flex items-center space-x-2.5'}>
|
||||
<div className={'flex items-center gap-x-4'}>
|
||||
<div className={'flex items-center gap-x-2.5'}>
|
||||
<ProfileAvatar
|
||||
pictureUrl={props.account.picture_url}
|
||||
displayName={props.account.name}
|
||||
@@ -89,7 +89,7 @@ async function PersonalAccountPage(props: { account: Account }) {
|
||||
</If>
|
||||
</div>
|
||||
|
||||
<div className={'flex space-x-1'}>
|
||||
<div className={'flex gap-x-1'}>
|
||||
<If condition={isBanned}>
|
||||
<AdminReactivateUserDialog userId={props.account.id}>
|
||||
<Button size={'sm'} variant={'ghost'}>
|
||||
@@ -124,10 +124,10 @@ async function PersonalAccountPage(props: { account: Account }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={'flex flex-col space-y-8'}>
|
||||
<div className={'flex flex-col gap-y-8'}>
|
||||
<SubscriptionsTable accountId={props.account.id} />
|
||||
|
||||
<div className={'divider-divider-x flex flex-col space-y-2.5'}>
|
||||
<div className={'divider-divider-x flex flex-col gap-y-2.5'}>
|
||||
<Heading level={6}>Teams</Heading>
|
||||
|
||||
<div>
|
||||
@@ -145,7 +145,7 @@ async function TeamAccountPage(props: {
|
||||
const members = await getMembers(props.account.slug ?? '');
|
||||
|
||||
return (
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<div className={'flex flex-col gap-y-4'}>
|
||||
<AppBreadcrumbs
|
||||
values={{
|
||||
[props.account.id]:
|
||||
@@ -154,8 +154,8 @@ async function TeamAccountPage(props: {
|
||||
/>
|
||||
|
||||
<div className={'flex justify-between'}>
|
||||
<div className={'flex items-center space-x-4'}>
|
||||
<div className={'flex items-center space-x-2.5'}>
|
||||
<div className={'flex items-center gap-x-4'}>
|
||||
<div className={'flex items-center gap-x-2.5'}>
|
||||
<ProfileAvatar
|
||||
pictureUrl={props.account.picture_url}
|
||||
displayName={props.account.name}
|
||||
@@ -178,10 +178,10 @@ async function TeamAccountPage(props: {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className={'flex flex-col space-y-8'}>
|
||||
<div className={'flex flex-col gap-y-8'}>
|
||||
<SubscriptionsTable accountId={props.account.id} />
|
||||
|
||||
<div className={'flex flex-col space-y-2.5'}>
|
||||
<div className={'flex flex-col gap-y-2.5'}>
|
||||
<Heading level={6}>Team Members</Heading>
|
||||
|
||||
<AdminMembersTable members={members} />
|
||||
|
||||
@@ -2,20 +2,20 @@ export function AuthLayoutShell({
|
||||
children,
|
||||
Logo,
|
||||
}: React.PropsWithChildren<{
|
||||
Logo: React.ComponentType;
|
||||
Logo?: React.ComponentType;
|
||||
}>) {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
'flex h-screen flex-col items-center justify-center' +
|
||||
' dark:lg:bg-background space-y-10 lg:space-y-12 lg:bg-gray-50' +
|
||||
' animate-in fade-in slide-in-from-top-8 zoom-in-95 duration-1000'
|
||||
' bg-background lg:bg-muted/30 gap-y-10 lg:gap-y-8' +
|
||||
' animate-in fade-in slide-in-from-top-16 zoom-in-95 duration-1000'
|
||||
}
|
||||
>
|
||||
{Logo && <Logo />}
|
||||
{Logo ? <Logo /> : null}
|
||||
|
||||
<div
|
||||
className={`bg-background dark:border-border flex w-full max-w-sm flex-col items-center space-y-5 rounded-lg border-transparent px-6 md:w-8/12 md:border md:px-8 md:py-6 md:shadow lg:w-5/12 lg:px-6 xl:w-4/12 xl:py-8 2xl:w-3/12 dark:shadow`}
|
||||
className={`bg-background flex w-full max-w-[23rem] flex-col gap-y-6 rounded-lg px-6 md:w-8/12 md:px-8 md:py-6 lg:w-5/12 lg:px-8 xl:w-4/12 xl:gap-y-8 xl:py-8`}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@ export function AuthProviderButton({
|
||||
}>) {
|
||||
return (
|
||||
<Button
|
||||
className={'flex w-full space-x-2 text-center'}
|
||||
className={'flex w-full gap-x-3 text-center'}
|
||||
data-provider={providerId}
|
||||
data-test={'auth-provider-button'}
|
||||
variant={'outline'}
|
||||
|
||||
@@ -75,13 +75,7 @@ export function PasswordResetRequestContainer(params: {
|
||||
})}
|
||||
className={'w-full'}
|
||||
>
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<div>
|
||||
<p className={'text-muted-foreground text-sm'}>
|
||||
<Trans i18nKey={'auth:passwordResetSubheading'} />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className={'flex flex-col gap-y-4'}>
|
||||
<AuthErrorAlert error={error} />
|
||||
|
||||
<FormField
|
||||
|
||||
@@ -43,7 +43,7 @@ export function PasswordSignInForm({
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
className={'w-full space-y-2.5'}
|
||||
className={'flex w-full flex-col gap-y-4'}
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
>
|
||||
<FormField
|
||||
@@ -91,17 +91,19 @@ export function PasswordSignInForm({
|
||||
|
||||
<FormMessage />
|
||||
|
||||
<Button
|
||||
asChild
|
||||
type={'button'}
|
||||
size={'sm'}
|
||||
variant={'link'}
|
||||
className={'text-xs'}
|
||||
>
|
||||
<Link href={'/auth/password-reset'}>
|
||||
<Trans i18nKey={'auth:passwordForgottenQuestion'} />
|
||||
</Link>
|
||||
</Button>
|
||||
<div>
|
||||
<Button
|
||||
asChild
|
||||
type={'button'}
|
||||
size={'sm'}
|
||||
variant={'link'}
|
||||
className={'text-xs'}
|
||||
>
|
||||
<Link href={'/auth/password-reset'}>
|
||||
<Trans i18nKey={'auth:passwordForgottenQuestion'} />
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -55,7 +55,7 @@ export function PasswordSignUpForm({
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
className={'w-full space-y-2.5'}
|
||||
className={'flex w-full flex-col gap-y-4'}
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
>
|
||||
<FormField
|
||||
|
||||
@@ -7,6 +7,7 @@ import type { Provider } from '@supabase/supabase-js';
|
||||
import { isBrowser } from '@kit/shared/utils';
|
||||
import { If } from '@kit/ui/if';
|
||||
import { Separator } from '@kit/ui/separator';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { MagicLinkAuthContainer } from './magic-link-auth-container';
|
||||
import { OauthProviders } from './oauth-providers';
|
||||
@@ -63,7 +64,17 @@ export function SignInMethodsContainer(props: {
|
||||
</If>
|
||||
|
||||
<If condition={props.providers.oAuth.length}>
|
||||
<Separator />
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<Separator />
|
||||
</div>
|
||||
|
||||
<div className="relative flex justify-center text-xs uppercase">
|
||||
<span className="bg-background text-muted-foreground px-2">
|
||||
<Trans i18nKey="auth:orContinueWith" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<OauthProviders
|
||||
enabledProviders={props.providers.oAuth}
|
||||
|
||||
@@ -55,7 +55,17 @@ export function SignUpMethodsContainer(props: {
|
||||
</If>
|
||||
|
||||
<If condition={props.providers.oAuth.length}>
|
||||
<Separator />
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<Separator />
|
||||
</div>
|
||||
|
||||
<div className="relative flex justify-center text-xs uppercase">
|
||||
<span className="bg-background text-muted-foreground px-2">
|
||||
<Trans i18nKey="auth:orContinueWith" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<OauthProviders
|
||||
enabledProviders={props.providers.oAuth}
|
||||
|
||||
@@ -16,7 +16,7 @@ export function TermsAndConditionsFormField(
|
||||
return (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<label className={'flex items-start space-x-2 py-2'}>
|
||||
<label className={'flex items-start gap-x-3 py-2'}>
|
||||
<Checkbox required name={field.name} />
|
||||
|
||||
<div className={'text-xs'}>
|
||||
|
||||
@@ -186,7 +186,7 @@ export function NotificationsPopover(params: {
|
||||
<div
|
||||
key={notification.id.toString()}
|
||||
className={cn(
|
||||
'min-h-18 flex flex-col items-start justify-center space-y-0.5 px-3 py-2',
|
||||
'min-h-18 flex flex-col items-start justify-center gap-y-1 px-3 py-2',
|
||||
)}
|
||||
onClick={() => {
|
||||
if (params.onClick) {
|
||||
@@ -196,7 +196,7 @@ export function NotificationsPopover(params: {
|
||||
>
|
||||
<div className={'flex w-full items-start justify-between'}>
|
||||
<div
|
||||
className={'flex items-start justify-start space-x-2 py-2'}
|
||||
className={'flex items-start justify-start gap-x-3 py-2'}
|
||||
>
|
||||
<div className={'py-0.5'}>
|
||||
<Icon />
|
||||
|
||||
@@ -138,7 +138,7 @@ function InviteMembersForm({
|
||||
data-test={'invite-members-form'}
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
>
|
||||
<div className="flex flex-col space-y-4">
|
||||
<div className="flex flex-col gap-y-4">
|
||||
{fieldArray.fields.map((field, index) => {
|
||||
const isFirst = index === 0;
|
||||
|
||||
@@ -147,7 +147,7 @@ function InviteMembersForm({
|
||||
|
||||
return (
|
||||
<div data-test={'invite-member-form-item'} key={field.id}>
|
||||
<div className={'flex items-end space-x-0.5 md:space-x-2'}>
|
||||
<div className={'flex items-end gap-x-1 md:space-x-2'}>
|
||||
<div className={'w-7/12'}>
|
||||
<FormField
|
||||
name={emailInputName}
|
||||
@@ -189,6 +189,7 @@ function InviteMembersForm({
|
||||
|
||||
<FormControl>
|
||||
<MembershipRoleSelector
|
||||
triggerClassName={'m-0'}
|
||||
roles={roles}
|
||||
value={field.value}
|
||||
onChange={(role) => {
|
||||
@@ -204,7 +205,7 @@ function InviteMembersForm({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={'flex w-[40px] justify-end'}>
|
||||
<div className={'flex w-[40px] items-end justify-end'}>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
|
||||
@@ -14,15 +14,20 @@ export function MembershipRoleSelector({
|
||||
value,
|
||||
currentUserRole,
|
||||
onChange,
|
||||
triggerClassName,
|
||||
}: {
|
||||
roles: Role[];
|
||||
value: Role;
|
||||
currentUserRole?: Role;
|
||||
onChange: (role: Role) => unknown;
|
||||
triggerClassName?: string;
|
||||
}) {
|
||||
return (
|
||||
<Select value={value} onValueChange={onChange}>
|
||||
<SelectTrigger data-test={'role-selector-trigger'}>
|
||||
<SelectTrigger
|
||||
className={triggerClassName}
|
||||
data-test={'role-selector-trigger'}
|
||||
>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user