WIP - styles Globals
This commit is contained in:
147
src/client/components/views/Global/Default.js
Normal file
147
src/client/components/views/Global/Default.js
Normal 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;
|
||||
@@ -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;
|
||||
|
||||
186
src/client/components/views/Global/index.scss
Normal file
186
src/client/components/views/Global/index.scss
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user