fix(ui, next): adjust modal alignment and padding (#7931)

## Description

Updates styling on modals and auth forms for more consistent spacing and
alignment.

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
This commit is contained in:
Tylan Davis
2024-09-06 14:54:39 -04:00
committed by GitHub
parent 6253ec5d1a
commit ead12c8a49
30 changed files with 535 additions and 278 deletions

View File

@@ -12,14 +12,14 @@
position: relative;
display: flex;
flex-direction: column;
gap: var(--base);
gap: base(0.8);
padding: base(2);
}
&__content {
display: flex;
flex-direction: column;
gap: var(--base);
gap: base(0.4);
> * {
margin: 0;
@@ -28,7 +28,7 @@
&__controls {
display: flex;
gap: var(--base);
gap: base(0.4);
.btn {
margin: 0;

View File

@@ -14,14 +14,14 @@
&--width-normal {
.template-minimal__wrap {
max-width: 500px;
max-width: base(24);
width: 100%;
}
}
&--width-wide {
.template-minimal__wrap {
max-width: 1024px;
max-width: base(48);
width: 100%;
}
}

View File

@@ -1,6 +1,16 @@
@import '../../scss/styles.scss';
.create-first-user {
display: flex;
flex-direction: column;
gap: base(0.4);
> form > .field-type {
margin-bottom: var(--base);
& .form-submit {
margin: 0;
}
}
}

View File

@@ -4,6 +4,10 @@ import { formatAdminURL } from '@payloadcms/ui/shared'
import LinkImport from 'next/link.js'
import React, { Fragment, useEffect } from 'react'
import './index.scss'
const baseClass = 'logout'
const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default
export const LogoutClient: React.FC<{
@@ -26,7 +30,7 @@ export const LogoutClient: React.FC<{
if (isLoggingOut) {
return (
<Fragment>
<div className={`${baseClass}__wrap`}>
{inactivity && <h2>{t('authentication:loggedOutInactivity')}</h2>}
{!inactivity && <h2>{t('authentication:loggedOutSuccessfully')}</h2>}
<Button
@@ -43,7 +47,7 @@ export const LogoutClient: React.FC<{
>
{t('authentication:logBackIn')}
</Button>
</Fragment>
</div>
)
}

View File

@@ -1,19 +1,22 @@
@import '../../scss/styles.scss';
.logout {
display: flex;
flex-direction: column;
align-items: center;
flex-wrap: wrap;
min-height: 100vh;
&__wrap {
& > *:first-child {
margin-top: 0;
}
z-index: 1;
position: relative;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: base(0.8);
width: 100%;
max-width: base(36);
& > *:last-child {
margin-bottom: 0;
}
.btn {
& > * {
margin: 0;
}
}

View File

@@ -25,7 +25,7 @@ export const LogoutView: React.FC<
} = initPageResult
return (
<div className={`${baseClass}__wrap`}>
<div className={`${baseClass}`}>
<LogoutClient
adminRoute={adminRoute}
inactivity={inactivity}

View File

@@ -38,8 +38,10 @@ export const NotFoundClient: React.FC<{
.join(' ')}
>
<Gutter className={`${baseClass}__wrap`}>
<div className={`${baseClass}__content`}>
<h1>{t('general:nothingFound')}</h1>
<p>{t('general:sorryNotFound')}</p>
</div>
<Button
className={`${baseClass}__button`}
el="link"

View File

@@ -13,6 +13,24 @@
}
}
&__wrap {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: base(0.8);
max-width: base(36);
}
&__content {
display: flex;
flex-direction: column;
gap: base(0.4);
> * {
margin: 0;
}
}
&__button {
margin: 0;
}

View File

@@ -75,6 +75,7 @@ export const ResetPasswordClient: React.FC<Args> = ({ token }) => {
method="POST"
onSuccess={onSuccess}
>
<div className={'inputWrap'}>
<PasswordField
field={{
name: 'password',
@@ -90,6 +91,7 @@ export const ResetPasswordClient: React.FC<Args> = ({ token }) => {
forceUsePathFromProps
value={token}
/>
</div>
<FormSubmit size="large">{i18n.t('authentication:resetPassword')}</FormSubmit>
</Form>
)

View File

@@ -1,5 +1,31 @@
@import '../../scss/styles.scss';
.reset-password {
form > .field-type {
margin-bottom: var(--base);
&__wrap {
z-index: 1;
position: relative;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: base(0.8);
max-width: base(36);
& > form {
width: 100%;
& > .inputWrap {
display: flex;
flex-direction: column;
gap: base(0.8);
> * {
margin: 0;
}
}
}
& > .btn {
margin: 0;
}
}
}

View File

@@ -1,11 +1,10 @@
import type { AdminViewProps } from 'payload'
import { Button, Translation } from '@payloadcms/ui'
import { formatAdminURL } from '@payloadcms/ui/shared'
import { Button } from '@payloadcms/ui'
import { formatAdminURL, Translation } from '@payloadcms/ui/shared'
import LinkImport from 'next/link.js'
import React from 'react'
import { MinimalTemplate } from '../../templates/Minimal/index.js'
import { ResetPasswordClient } from './index.client.js'
import './index.scss'
@@ -37,7 +36,6 @@ export const ResetPassword: React.FC<AdminViewProps> = ({ initPageResult, params
if (user) {
return (
<MinimalTemplate className={resetPasswordBaseClass}>
<div className={`${resetPasswordBaseClass}__wrap`}>
<h1>{i18n.t('authentication:alreadyLoggedIn')}</h1>
<p>
@@ -58,21 +56,17 @@ export const ResetPassword: React.FC<AdminViewProps> = ({ initPageResult, params
t={i18n.t}
/>
</p>
<br />
<Button buttonStyle="secondary" el="link" Link={Link} to={adminRoute}>
<Button buttonStyle="secondary" el="link" Link={Link} size="large" to={adminRoute}>
{i18n.t('general:backToDashboard')}
</Button>
</div>
</MinimalTemplate>
)
}
return (
<MinimalTemplate className={resetPasswordBaseClass}>
<div className={`${resetPasswordBaseClass}__wrap`}>
<h1>{i18n.t('authentication:resetPassword')}</h1>
<ResetPasswordClient token={token} />
</div>
</MinimalTemplate>
)
}

View File

@@ -38,24 +38,40 @@
@include blur-bg;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
&__toggle {
@extend %btn-reset;
}
}
&__wrapper {
z-index: 1;
position: relative;
display: flex;
flex-direction: column;
gap: base(0.8);
padding: base(2);
max-width: base(36);
}
&__content {
display: flex;
flex-direction: column;
gap: base(0.4);
> * {
margin: 0;
}
}
&__controls {
display: flex;
gap: base(0.4);
.btn {
[dir='ltr'] & {
margin-right: var(--base);
}
[dir='rtl'] & {
margin-left: var(--base);
margin: 0;
}
}
}
&__modal-template {
position: relative;
z-index: 1;
}
}

View File

@@ -18,7 +18,6 @@ import { toast } from 'sonner'
import type { Props } from './types.js'
import { MinimalTemplate } from '../../../templates/Minimal/index.js'
import './index.scss'
const baseClass = 'restore-version'
@@ -123,12 +122,16 @@ const Restore: React.FC<Props> = ({
)}
</div>
<Modal className={`${baseClass}__modal`} slug={modalSlug}>
<MinimalTemplate className={`${baseClass}__modal-template`}>
<div className={`${baseClass}__wrapper`}>
<div className={`${baseClass}__content`}>
<h1>{t('version:confirmVersionRestoration')}</h1>
<p>{restoreMessage}</p>
</div>
<div className={`${baseClass}__controls`}>
<Button
buttonStyle="secondary"
onClick={processing ? undefined : () => toggleModal(modalSlug)}
size="large"
type="button"
>
{t('general:cancel')}
@@ -136,7 +139,8 @@ const Restore: React.FC<Props> = ({
<Button onClick={processing ? undefined : () => void handleRestore()}>
{processing ? t('version:restoring') : t('general:confirm')}
</Button>
</MinimalTemplate>
</div>
</div>
</Modal>
</Fragment>
)

View File

@@ -4,26 +4,39 @@
@include blur-bg;
display: flex;
align-items: center;
height: 100%;
justify-content: center;
padding: base(2);
&__template {
z-index: 1;
position: relative;
}
height: 100%;
&__toggle {
@extend %btn-reset;
}
&__wrapper {
z-index: 1;
position: relative;
display: flex;
flex-direction: column;
gap: base(0.8);
padding: base(2);
max-width: base(36);
}
&__content {
display: flex;
flex-direction: column;
gap: base(0.4);
> * {
margin: 0;
}
}
&__controls {
display: flex;
gap: base(0.4);
.btn {
margin: 0;
}
&__actions {
display: flex;
flex-wrap: wrap;
gap: $baseline;
}
}

View File

@@ -129,7 +129,8 @@ export const DeleteDocument: React.FC<Props> = (props) => {
{t('general:delete')}
</PopupList.Button>
<Modal className={baseClass} slug={modalSlug}>
<div className={`${baseClass}__template`}>
<div className={`${baseClass}__wrapper`}>
<div className={`${baseClass}__content`}>
<h1>{t('general:confirmDeletion')}</h1>
<p>
<Translation
@@ -144,16 +145,22 @@ export const DeleteDocument: React.FC<Props> = (props) => {
}}
/>
</p>
<div className={`${baseClass}__actions`}>
</div>
<div className={`${baseClass}__controls`}>
<Button
buttonStyle="secondary"
id="confirm-cancel"
onClick={deleting ? undefined : () => toggleModal(modalSlug)}
size="large"
type="button"
>
{t('general:cancel')}
</Button>
<Button id="confirm-delete" onClick={deleting ? undefined : handleDelete}>
<Button
id="confirm-delete"
onClick={deleting ? undefined : handleDelete}
size="large"
>
{deleting ? t('general:deleting') : t('general:confirm')}
</Button>
</div>

View File

@@ -4,16 +4,35 @@
@include blur-bg;
display: flex;
align-items: center;
height: 100%;
justify-content: center;
padding: base(2);
height: 100%;
&__template {
&__wrapper {
z-index: 1;
position: relative;
display: flex;
flex-direction: column;
gap: base(0.8);
padding: base(2);
max-width: base(36);
}
&__content {
display: flex;
flex-direction: column;
gap: base(0.4);
> * {
margin: 0;
}
}
&__controls {
display: flex;
gap: base(0.4);
.btn {
margin-right: $baseline;
margin: 0;
}
}
}

View File

@@ -125,21 +125,26 @@ export const DeleteMany: React.FC<Props> = (props) => {
{t('general:delete')}
</Pill>
<Modal className={baseClass} slug={modalSlug}>
<div className={`${baseClass}__template`}>
<div className={`${baseClass}__wrapper`}>
<div className={`${baseClass}__content`}>
<h1>{t('general:confirmDeletion')}</h1>
<p>{t('general:aboutToDeleteCount', { count, label: getTranslation(plural, i18n) })}</p>
</div>
<div className={`${baseClass}__controls`}>
<Button
buttonStyle="secondary"
id="confirm-cancel"
onClick={deleting ? undefined : () => toggleModal(modalSlug)}
size="large"
type="button"
>
{t('general:cancel')}
</Button>
<Button id="confirm-delete" onClick={deleting ? undefined : handleDelete}>
<Button id="confirm-delete" onClick={deleting ? undefined : handleDelete} size="large">
{deleting ? t('general:deleting') : t('general:confirm')}
</Button>
</div>
</div>
</Modal>
</React.Fragment>
)

View File

@@ -5,16 +5,36 @@
@include blur-bg;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding: base(2);
.btn {
margin-right: $baseline;
}
}
&__modal-template {
&__wrapper {
z-index: 1;
position: relative;
display: flex;
flex-direction: column;
gap: base(0.8);
padding: base(2);
max-width: base(36);
}
&__content {
display: flex;
flex-direction: column;
gap: base(0.4);
> * {
margin: 0;
}
}
&__controls {
display: flex;
gap: base(0.4);
.btn {
margin: 0;
}
}
}

View File

@@ -118,21 +118,26 @@ export const DuplicateDocument: React.FC<Props> = ({ id, slug, singularLabel })
</PopupList.Button>
{modified && hasClicked && (
<Modal className={`${baseClass}__modal`} slug={modalSlug}>
<div className={`${baseClass}__modal-template`}>
<div className={`${baseClass}__wrapper`}>
<div className={`${baseClass}__content`}>
<h1>{t('general:confirmDuplication')}</h1>
<p>{t('general:unsavedChangesDuplicate')}</p>
</div>
<div className={`${baseClass}__controls`}>
<Button
buttonStyle="secondary"
id="confirm-cancel"
onClick={() => toggleModal(modalSlug)}
size="large"
type="button"
>
{t('general:cancel')}
</Button>
<Button id="confirm-duplicate" onClick={() => void confirm()}>
<Button id="confirm-duplicate" onClick={() => void confirm()} size="large">
{t('general:duplicateWithoutSaving')}
</Button>
</div>
</div>
</Modal>
)}
</React.Fragment>

View File

@@ -6,14 +6,33 @@
align-items: center;
justify-content: center;
height: 100%;
padding: base(2);
&__template {
position: relative;
&__wrapper {
z-index: 1;
position: relative;
display: flex;
flex-direction: column;
gap: base(0.8);
padding: base(2);
max-width: base(36);
}
&__content {
display: flex;
flex-direction: column;
gap: base(0.4);
> * {
margin: 0;
}
}
&__controls {
display: flex;
gap: base(0.4);
.btn {
margin-right: $baseline;
margin: 0;
}
}
}

View File

@@ -44,7 +44,8 @@ export const GenerateConfirmation: React.FC<GenerateConfirmationProps> = (props)
{t('authentication:generateNewAPIKey')}
</Button>
<Modal className={baseClass} slug={modalSlug}>
<div className={`${baseClass}__template`}>
<div className={`${baseClass}__wrapper`}>
<div className={`${baseClass}__content`}>
<h1>{t('authentication:confirmGeneration')}</h1>
<p>
<Translation
@@ -55,18 +56,21 @@ export const GenerateConfirmation: React.FC<GenerateConfirmationProps> = (props)
t={t}
/>
</p>
</div>
<div className={`${baseClass}__controls`}>
<Button
buttonStyle="secondary"
onClick={() => {
toggleModal(modalSlug)
}}
size="large"
type="button"
>
{t('general:cancel')}
</Button>
<Button onClick={handleGenerate}>{t('authentication:generate')}</Button>
</div>
</div>
</Modal>
</React.Fragment>
)

View File

@@ -4,15 +4,34 @@
@include blur-bg;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding: base(2);
&__template {
&__wrapper {
z-index: 1;
position: relative;
display: flex;
flex-direction: column;
gap: base(0.8);
padding: base(2);
}
&__content {
display: flex;
flex-direction: column;
gap: base(0.4);
> * {
margin: 0;
}
}
&__controls {
display: flex;
gap: base(0.4);
.btn {
margin-right: $baseline;
margin: 0;
}
}
}

View File

@@ -127,21 +127,30 @@ export const PublishMany: React.FC<PublishManyProps> = (props) => {
{t('version:publish')}
</Pill>
<Modal className={baseClass} slug={modalSlug}>
<div className={`${baseClass}__template`}>
<div className={`${baseClass}__wrapper`}>
<div className={`${baseClass}__content`}>
<h1>{t('version:confirmPublish')}</h1>
<p>{t('version:aboutToPublishSelection', { label: getTranslation(plural, i18n) })}</p>
</div>
<div className={`${baseClass}__controls`}>
<Button
buttonStyle="secondary"
id="confirm-cancel"
onClick={submitted ? undefined : () => toggleModal(modalSlug)}
size="large"
type="button"
>
{t('general:cancel')}
</Button>
<Button id="confirm-publish" onClick={submitted ? undefined : handlePublish}>
<Button
id="confirm-publish"
onClick={submitted ? undefined : handlePublish}
size="large"
>
{submitted ? t('version:publishing') : t('general:confirm')}
</Button>
</div>
</div>
</Modal>
</React.Fragment>
)

View File

@@ -20,22 +20,41 @@
&__modal {
@include blur-bg;
display: flex;
justify-content: center;
align-items: center;
justify-content: center;
height: 100%;
padding: base(2);
&__toggle {
@extend %btn-reset;
}
}
&__wrapper {
z-index: 1;
position: relative;
display: flex;
flex-direction: column;
gap: base(0.8);
padding: base(2);
max-width: base(36);
}
&__content {
display: flex;
flex-direction: column;
gap: base(0.4);
> * {
margin: 0;
}
}
&__controls {
display: flex;
gap: base(0.4);
.btn {
margin-right: $baseline;
margin: 0;
}
}
&__modal-template {
position: relative;
z-index: 1;
}
}

View File

@@ -152,20 +152,28 @@ export const Status: React.FC = () => {
{t('version:unpublish')}
</Button>
<Modal className={`${baseClass}__modal`} slug={unPublishModalSlug}>
<div className={`${baseClass}__modal-template`}>
<div className={`${baseClass}__wrapper`}>
<div className={`${baseClass}__content`}>
<h1>{t('version:confirmUnpublish')}</h1>
<p>{t('version:aboutToUnpublish')}</p>
</div>
<div className={`${baseClass}__controls`}>
<Button
buttonStyle="secondary"
onClick={processing ? undefined : () => toggleModal(unPublishModalSlug)}
size="large"
type="button"
>
{t('general:cancel')}
</Button>
<Button onClick={processing ? undefined : () => performAction('unpublish')}>
<Button
onClick={processing ? undefined : () => performAction('unpublish')}
size="large"
>
{t(processing ? 'version:unpublishing' : 'general:confirm')}
</Button>
</div>
</div>
</Modal>
</React.Fragment>
)}
@@ -181,12 +189,16 @@ export const Status: React.FC = () => {
{t('version:revertToPublished')}
</Button>
<Modal className={`${baseClass}__modal`} slug={revertModalSlug}>
<div className={`${baseClass}__modal-template`}>
<div className={`${baseClass}__wrapper`}>
<div className={`${baseClass}__content`}>
<h1>{t('version:confirmRevertToSaved')}</h1>
<p>{t('version:aboutToRevertToPublished')}</p>
</div>
<div className={`${baseClass}__controls`}>
<Button
buttonStyle="secondary"
onClick={processing ? undefined : () => toggleModal(revertModalSlug)}
size="large"
type="button"
>
{t('general:cancel')}
@@ -194,10 +206,12 @@ export const Status: React.FC = () => {
<Button
id="action-revert-to-published-confirm"
onClick={processing ? undefined : () => performAction('revert')}
size="large"
>
{t(processing ? 'version:reverting' : 'general:confirm')}
</Button>
</div>
</div>
</Modal>
</React.Fragment>
)}

View File

@@ -1,4 +1,3 @@
'use client'
import type { ClientTranslationKeys, TFunction } from '@payloadcms/translations'
import * as React from 'react'

View File

@@ -4,15 +4,34 @@
@include blur-bg;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding: base(2);
&__template {
&__wrapper {
z-index: 1;
position: relative;
display: flex;
flex-direction: column;
gap: base(0.8);
padding: base(2);
}
&__content {
display: flex;
flex-direction: column;
gap: base(0.4);
> * {
margin: 0;
}
}
&__controls {
display: flex;
gap: base(0.4);
.btn {
margin-right: $baseline;
margin: 0;
}
}
}

View File

@@ -124,21 +124,30 @@ export const UnpublishMany: React.FC<UnpublishManyProps> = (props) => {
{t('version:unpublish')}
</Pill>
<Modal className={baseClass} slug={modalSlug}>
<div className={`${baseClass}__template`}>
<div className={`${baseClass}__wrapper`}>
<div className={`${baseClass}__content`}>
<h1>{t('version:confirmUnpublish')}</h1>
<p>{t('version:aboutToUnpublishSelection', { label: getTranslation(plural, i18n) })}</p>
</div>
<div className={`${baseClass}__controls`}>
<Button
buttonStyle="secondary"
id="confirm-cancel"
onClick={submitted ? undefined : () => toggleModal(modalSlug)}
size="large"
type="button"
>
{t('general:cancel')}
</Button>
<Button id="confirm-unpublish" onClick={submitted ? undefined : handleUnpublish}>
<Button
id="confirm-unpublish"
onClick={submitted ? undefined : handleUnpublish}
size="large"
>
{submitted ? t('version:unpublishing') : t('general:confirm')}
</Button>
</div>
</div>
</Modal>
</React.Fragment>
)

View File

@@ -1,4 +1,5 @@
// IMPORTANT: the shared.ts file CANNOT contain any Server Components _that import client components_.
export { Translation } from '../../elements/Translation/index.js'
export { withMergedProps } from '../../elements/withMergedProps/index.js' // cannot be within a 'use client', thus we export this from shared
export { WithServerSideProps } from '../../elements/WithServerSideProps/index.js'
export { PayloadIcon } from '../../graphics/Icon/index.js'

View File

@@ -1,7 +1,5 @@
// DO NOT MODIFY. This file is automatically generated in initDevAndTest.ts
import { mongooseAdapter } from '@payloadcms/db-mongodb'
export const databaseAdapter = mongooseAdapter({
@@ -13,4 +11,3 @@
strength: 1,
},
})