WIP - styles Globals

This commit is contained in:
James
2020-07-06 22:58:31 -04:00
parent 83567c68db
commit b263e04408
16 changed files with 418 additions and 113 deletions

View File

@@ -0,0 +1,147 @@
import React from 'react';
import PropTypes from 'prop-types';
import format from 'date-fns/format';
import config from 'payload/config';
import Eyebrow from '../../elements/Eyebrow';
import Form from '../../forms/Form';
import PreviewButton from '../../elements/PreviewButton';
import FormSubmit from '../../forms/Submit';
import RenderFields from '../../forms/RenderFields';
import CopyToClipboard from '../../elements/CopyToClipboard';
import * as fieldTypes from '../../forms/field-types';
import LeaveWithoutSaving from '../../modals/LeaveWithoutSaving';
import './index.scss';
const { serverURL, routes: { api } } = config;
const baseClass = 'global-edit';
const DefaultGlobalView = (props) => {
const {
global, data, onSave, permissions,
} = props;
const {
slug,
fields,
preview,
label,
} = global;
const apiURL = `${serverURL}${api}/globals/${slug}`;
const action = `${serverURL}${api}/globals/${slug}`;
const hasSavePermission = permissions?.update?.permission;
return (
<div className={baseClass}>
<Form
className={`${baseClass}__form`}
method="post"
action={action}
onSuccess={onSave}
disabled={!hasSavePermission}
>
<div className={`${baseClass}__main`}>
<Eyebrow />
<LeaveWithoutSaving />
<div className={`${baseClass}__edit`}>
<header className={`${baseClass}__header`}>
<h1>
Edit
{' '}
{label}
</h1>
</header>
<RenderFields
operation="update"
readOnly={!hasSavePermission}
permissions={permissions.fields}
filter={field => (!field.position || (field.position && field.position !== 'sidebar'))}
fieldTypes={fieldTypes}
fieldSchema={fields}
initialData={data}
customComponentsPath={`${slug}.fields.`}
/>
</div>
</div>
<div className={`${baseClass}__sidebar`}>
<div className={`${baseClass}__document-actions${preview ? ` ${baseClass}__document-actions--with-preview` : ''}`}>
<PreviewButton generatePreviewURL={preview} />
{hasSavePermission && (
<FormSubmit>Save</FormSubmit>
)}
</div>
{data && (
<div className={`${baseClass}__api-url`}>
<span className={`${baseClass}__label`}>
API URL
{' '}
<CopyToClipboard value={apiURL} />
</span>
<a
href={apiURL}
target="_blank"
rel="noopener noreferrer"
>
{apiURL}
</a>
</div>
)}
<div className={`${baseClass}__sidebar-fields`}>
<RenderFields
operation="update"
readOnly={!hasSavePermission}
permissions={permissions.fields}
filter={field => field.position === 'sidebar'}
position="sidebar"
fieldTypes={fieldTypes}
fieldSchema={fields}
initialData={data}
customComponentsPath={`${slug}.fields.`}
/>
</div>
{data && (
<ul className={`${baseClass}__meta`}>
{data && (
<>
{data.updatedAt && (
<li>
<div className={`${baseClass}__label`}>Last Modified</div>
<div>{format(new Date(data.updatedAt), 'MMMM do yyyy, h:mma')}</div>
</li>
)}
</>
)}
</ul>
)}
</div>
</Form>
</div>
);
};
DefaultGlobalView.defaultProps = {
data: undefined,
};
DefaultGlobalView.propTypes = {
global: PropTypes.shape({
label: PropTypes.string.isRequired,
slug: PropTypes.string,
fields: PropTypes.arrayOf(PropTypes.shape({})),
preview: PropTypes.func,
}).isRequired,
data: PropTypes.shape({
updatedAt: PropTypes.string,
}),
onSave: PropTypes.func.isRequired,
permissions: PropTypes.shape({
update: PropTypes.shape({
permission: PropTypes.bool,
}),
fields: PropTypes.shape({}),
}).isRequired,
};
export default DefaultGlobalView;

View File

@@ -1,68 +1,76 @@
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { useHistory, useLocation } from 'react-router-dom';
import config from 'payload/config';
import { useStepNav } from '../../elements/StepNav';
import usePayloadAPI from '../../../hooks/usePayloadAPI';
import Form from '../../forms/Form';
import RenderFields from '../../forms/RenderFields';
import * as fieldTypes from '../../forms/field-types';
import { useUser } from '../../data/User';
const {
serverURL,
routes: {
admin,
api,
},
} = config;
import RenderCustomComponent from '../../utilities/RenderCustomComponent';
import DefaultGlobal from './Default';
const baseClass = 'global-edit';
const { serverURL, routes: { admin, api } } = config;
const Global = (props) => {
const { global: { slug, label, fields } } = props;
const GlobalView = (props) => {
const { state: locationState } = useLocation();
const history = useHistory();
const { setStepNav } = useStepNav();
const { permissions } = useUser();
const { global } = props;
const {
slug,
label,
} = global;
const onSave = (json) => {
history.push(`${admin}/globals/${global.slug}`, {
status: {
message: json.message,
type: 'success',
},
data: json.doc,
});
};
const [{ data }] = usePayloadAPI(
`${serverURL}${api}/globals/${slug}`,
{ initialParams: { 'fallback-locale': 'null' } },
);
const dataToRender = locationState?.data || data;
useEffect(() => {
setStepNav([{
url: `${admin}/globals/${slug}`,
const nav = [{
label,
}]);
}, [setStepNav, slug, label]);
}];
setStepNav(nav);
}, [setStepNav, label]);
const globalPermissions = permissions?.[slug];
return (
<div className={baseClass}>
<header className={`${baseClass}__header`}>
<h1>
Edit
{' '}
{label}
</h1>
</header>
<Form
className={`${baseClass}__form`}
method={data ? 'put' : 'post'}
action={`${serverURL}${api}/globals/${slug}`}
>
<RenderFields
fieldTypes={fieldTypes}
fieldSchema={fields}
initialData={data}
/>
</Form>
</div>
<RenderCustomComponent
DefaultComponent={DefaultGlobal}
path={`${slug}.views.Edit`}
componentProps={{
data: dataToRender,
permissions: globalPermissions,
global,
onSave,
}}
/>
);
};
Global.propTypes = {
GlobalView.propTypes = {
global: PropTypes.shape({
label: PropTypes.string,
slug: PropTypes.string,
label: PropTypes.string.isRequired,
slug: PropTypes.string.isRequired,
fields: PropTypes.arrayOf(PropTypes.shape({})),
}).isRequired,
};
export default Global;
export default GlobalView;

View File

@@ -0,0 +1,186 @@
@import '../../../scss/styles.scss';
.global-edit {
width: 100%;
&__form {
display: flex;
align-items: stretch;
}
&__main {
min-width: 0;
}
&__header {
h1 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
&__collection-actions {
list-style: none;
margin: 0;
padding: base(1.5) 0 base(.5);
display: flex;
li {
margin-right: base(.75);
}
}
&__edit {
background: white;
padding: base(5) base(6) base(6);
}
&__sidebar {
padding-top: base(3);
padding-bottom: base(1);
width: base(22);
display: flex;
flex-direction: column;
min-width: 0;
}
&__collection-actions,
&__document-actions,
&__meta,
&__sidebar-fields,
&__api-url {
padding-left: base(1.5);
}
&__document-actions {
@include blur-bg;
position: sticky;
top: 0;
z-index: 2;
padding-right: $baseline;
}
&__document-actions--with-preview {
display: flex;
> * {
width: calc(50% - #{base(.5)});
}
> *:first-child {
margin-right: base(.5);
}
> *:last-child {
margin-left: base(.5);
}
.form-submit {
.btn {
width: 100%;
padding-left: base(2);
padding-right: base(2);
}
}
}
&__api-url {
margin-bottom: base(1.5);
padding-right: base(1.5);
a {
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
}
&__meta {
margin: 0;
padding-top: $baseline;
list-style: none;
li {
margin-bottom: base(.5);
}
}
&__label {
color: $color-gray;
}
&__collection-actions,
&__api-url {
a, button {
cursor: pointer;
font-weight: 600;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
&--is-editing {
.collection-edit__sidebar {
padding-top: 0;
}
}
@include large-break {
&__edit {
padding: base(3.5);
}
}
@include mid-break {
&__sidebar {
width: unset;
}
&__form {
display: block;
}
&__edit {
padding: $baseline;
margin-bottom: $baseline;
}
&__document-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
top: auto;
}
&__document-actions,
&__meta,
&__sidebar-fields,
&__api-url {
padding-left: $baseline;
}
&__api-url {
margin-bottom: base(.5);
}
&__collection-actions {
margin-top: base(.5);
padding-left: $baseline;
padding-bottom: 0;
order: 1;
li {
margin: 0 base(.5) 0 0;
}
}
&__sidebar {
padding-bottom: base(4);
}
}
}

View File

@@ -39,7 +39,7 @@ const DefaultEditView = (props) => {
const apiURL = `${serverURL}${api}/${slug}/${id}`;
let action = `${serverURL}${api}/${slug}${isEditing ? `/${id}` : ''}`;
const hasSavePermission = (isEditing && permissions?.update?.permission) || (!isEditing && permissions?.update?.permission);
const hasSavePermission = (isEditing && permissions?.update?.permission) || (!isEditing && permissions?.create?.permission);
if (auth && !isEditing) {
action = `${action}/register`;
@@ -170,7 +170,6 @@ const DefaultEditView = (props) => {
DefaultEditView.defaultProps = {
isEditing: false,
data: undefined,
onSave: null,
};
DefaultEditView.propTypes = {
@@ -191,7 +190,7 @@ DefaultEditView.propTypes = {
updatedAt: PropTypes.string,
createdAt: PropTypes.string,
}),
onSave: PropTypes.func,
onSave: PropTypes.func.isRequired,
permissions: PropTypes.shape({
create: PropTypes.shape({
permission: PropTypes.bool,