Fix all single types feedback

Signed-off-by: HichamELBSI <elabbassih@gmail.com>
This commit is contained in:
HichamELBSI 2020-02-28 11:51:57 +01:00
parent d5d5c0fb4f
commit 92632be70d
36 changed files with 238 additions and 192 deletions

View File

@ -8,7 +8,8 @@ const FaIcon = styled(({ small, ...props }) => <FontAwesomeIcon {...props} />)`
top: calc(50% - 0.9rem + 0.3rem);
left: 1.6rem;
margin-right: 1.2rem;
font-size: ${props => (props.small ? '1rem' : '1.4rem')};
margin-top: ${({ small }) => (small ? '.3rem' : null)};
font-size: ${({ small }) => (small ? '.9rem' : '1.4rem')};
width: 1.4rem;
padding-bottom: 0.2rem;
text-align: center;

View File

@ -4,8 +4,8 @@ const Search = styled.input`
width: 100%;
padding: 0 15px;
outline: 0;
font-size: 1.2rem;
color: ${props => props.theme.main.colors.white};
font-size: 1.1rem;
color: ${({ theme }) => theme.main.colors.white};
`;
export default Search;

View File

@ -2,6 +2,7 @@ import styled from 'styled-components';
const SearchButton = styled.button`
padding: 0 10px;
line-height: normal;
`;
export default SearchButton;

View File

@ -0,0 +1,10 @@
import styled from 'styled-components';
const SearchWrapper = styled.div`
display: flex;
width: 100%;
justify-content: space-between;
border-bottom: 1px solid;
`;
export default SearchWrapper;

View File

@ -6,13 +6,13 @@ const Title = styled.div`
padding-left: 2rem;
padding-right: 1.6rem;
padding-top: 1rem;
margin-bottom: 0.8rem;
margin-bottom: 0.9rem;
color: ${props => props.theme.main.colors.leftMenu['title-color']};
text-transform: uppercase;
font-size: 1.2rem;
font-size: 1.1rem;
letter-spacing: 0.1rem;
font-weight: 800;
max-height: 28px;
max-height: 26px;
`;
Title.defaultProps = {

View File

@ -8,6 +8,7 @@ import messages from '../LeftMenuLinkContainer/messages.json';
import Search from './Search';
import Title from './Title';
import SearchButton from './SearchButton';
import SearchWrapper from './SearchWrapper';
const LeftMenuLinkHeader = ({ section, searchable, setSearch, search }) => {
const [showSearch, setShowSearch] = useState(false);
@ -33,34 +34,33 @@ const LeftMenuLinkHeader = ({ section, searchable, setSearch, search }) => {
setShowSearch(false);
};
return !showSearch ? (
return (
<Title>
<FormattedMessage id={id} defaultMessage={defaultMessage} />
{searchable && (
<SearchButton onClick={toggleSearch}>
<FontAwesomeIcon icon="search" />
</SearchButton>
{!showSearch ? (
<>
<FormattedMessage id={id} defaultMessage={defaultMessage} />
{searchable && (
<SearchButton onClick={toggleSearch}>
<FontAwesomeIcon icon="search" />
</SearchButton>
)}
</>
) : (
<SearchWrapper>
<div>
<FontAwesomeIcon style={{ fontSize: 12 }} icon="search" />
</div>
<FormattedMessage id="components.Search.placeholder">
{message => (
<Search ref={ref} onChange={handleChange} value={search} placeholder={message} />
)}
</FormattedMessage>
<SearchButton onClick={clearSearch}>
<FontAwesomeIcon icon="times" />
</SearchButton>
</SearchWrapper>
)}
</Title>
) : (
<Title>
<div>
<FontAwesomeIcon icon="search" />
</div>
<FormattedMessage id="components.Search.placeholder">
{message => (
<Search
ref={ref}
onChange={handleChange}
value={search}
placeholder={message}
/>
)}
</FormattedMessage>
<SearchButton onClick={clearSearch}>
<FontAwesomeIcon icon="times" />
</SearchButton>
</Title>
);
};

View File

@ -1,12 +1,11 @@
import styled from 'styled-components';
const EmptyLinksList = styled.div`
color: ${props => props.theme.main.colors.white};
padding-left: 1.6rem;
padding-right: 1.6rem;
font-weight: 300;
const EmptyLinksList = styled.span`
min-height: 3.6rem;
padding-top: 0.6rem;
padding: 0.6rem 1.6rem 2.6rem 0;
font-size: 1.4rem;
font-weight: 400;
color: ${({ theme }) => theme.main.colors.leftMenu['link-color']};
`;
EmptyLinksList.defaultProps = {

View File

@ -0,0 +1,8 @@
import styled from 'styled-components';
const EmptyLinksListWrapper = styled.div`
padding: 0.7rem 0;
margin-bottom: 0.1rem;
`;
export default EmptyLinksListWrapper;

View File

@ -2,6 +2,7 @@ import styled from 'styled-components';
const LeftMenuListLink = styled.div`
max-height: 180px;
margin-bottom: 0.1rem;
overflow: auto;
`;

View File

@ -6,16 +6,11 @@ import { FormattedMessage } from 'react-intl';
import LeftMenuLink from '../LeftMenuLink';
import LeftMenuLinkHeader from '../LeftMenuLinkHeader';
import EmptyLinksList from './EmptyLinksList';
import LeftMenuListLink from './LeftMenuListLink';
import EmptyLinksList from './EmptyLinksList';
import EmptyLinksListWrapper from './EmptyLinksListWrapper';
const LeftMenuLinksSection = ({
section,
searchable,
location,
links,
emptyLinksListMessage,
}) => {
const LeftMenuLinksSection = ({ section, searchable, location, links, emptyLinksListMessage }) => {
const [search, setSearch] = useState('');
const filteredList = sortBy(
@ -30,8 +25,7 @@ const LeftMenuLinksSection = ({
return link.destination;
}
if (link.schema && link.schema.kind) {
return `/plugins/${link.plugin}/${link.schema.kind}/${link.destination ||
link.uid}`;
return `/plugins/${link.plugin}/${link.schema.kind}/${link.destination || link.uid}`;
}
return `/plugins/${link.plugin}/${link.destination || link.uid}`;
@ -59,12 +53,11 @@ const LeftMenuLinksSection = ({
/>
))
) : (
<EmptyLinksList>
<FormattedMessage
id={emptyLinksListMessage}
defaultMessage="No plugins installed yet"
/>
</EmptyLinksList>
<EmptyLinksListWrapper>
<FormattedMessage id={emptyLinksListMessage} defaultMessage="No plugins installed yet">
{msg => <EmptyLinksList>{msg}</EmptyLinksList>}
</FormattedMessage>
</EmptyLinksListWrapper>
)}
</LeftMenuListLink>
</>

View File

@ -105,7 +105,7 @@ const GlobalNotification = createGlobalStyle`
const Li = styled.li`
position: relative;
display: flex;
align-items: stretch;
align-items: center;
width: 300px;
min-height: 60px;
margin-bottom: 14px;
@ -116,6 +116,7 @@ const Li = styled.li`
transition: all 0.15s ease;
overflow: hidden;
z-index: 10;
padding: 1rem;
// The last notification must appear from
// the background of the previous one.

View File

@ -11,15 +11,7 @@ import { auth } from 'strapi-helper-plugin';
import PageTitle from '../../components/PageTitle';
import useFetch from './hooks';
import {
ALink,
Block,
Container,
LinkWrapper,
P,
Wave,
Separator,
} from './components';
import { ALink, Block, Container, LinkWrapper, P, Wave, Separator } from './components';
import BlogPost from './BlogPost';
import SocialLink from './SocialLink';
@ -74,11 +66,9 @@ const HomePage = ({ global: { plugins }, history: { push } }) => {
);
};
const hasAlreadyCreatedContentTypes =
get(
plugins,
['content-manager', 'leftMenuSections', '0', 'links'],
[]
).filter(contentType => contentType.isDisplayed === true).length > 1;
get(plugins, ['content-manager', 'leftMenuSections', '0', 'links'], []).filter(
contentType => contentType.isDisplayed === true
).length > 1;
const headerId = hasAlreadyCreatedContentTypes
? 'HomePage.greetings'
@ -133,7 +123,7 @@ const HomePage = ({ global: { plugins }, history: { push } }) => {
return (
<P>
<b>{congrats}</b>&nbsp;
{content} &nbsp;
{content}&nbsp;
<b>{boldContent}</b>
</P>
);
@ -176,12 +166,7 @@ const HomePage = ({ global: { plugins }, history: { push } }) => {
const type = index === 0 ? 'doc' : 'code';
return (
<LinkWrapper
href={data.link}
target="_blank"
key={data.link}
type={type}
>
<LinkWrapper href={data.link} target="_blank" key={data.link} type={type}>
<FormattedMessage id={data.titleId}>
{title => <p className="bold">{title}</p>}
</FormattedMessage>
@ -197,13 +182,9 @@ const HomePage = ({ global: { plugins }, history: { push } }) => {
<div className="col-md-12 col-lg-4">
<Block style={{ paddingRight: 30, paddingBottom: 0 }}>
<FormattedMessage id="HomePage.community">
{msg => <h2>{msg}</h2>}
</FormattedMessage>
<FormattedMessage id="HomePage.community">{msg => <h2>{msg}</h2>}</FormattedMessage>
<FormattedMessage id="app.components.HomePage.community.content">
{content => (
<P style={{ marginTop: 7, marginBottom: 0 }}>{content}</P>
)}
{content => <P style={{ marginTop: 7, marginBottom: 0 }}>{content}</P>}
</FormattedMessage>
<FormattedMessage id="HomePage.roadmap">
{msg => (

View File

@ -1,25 +1,31 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { isObject } from 'lodash';
import { Collapse } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import useFormattedMessage from '../../hooks/useFormattedMessage';
import { useGlobalContext } from '../../contexts/GlobalContext';
import LeftMenuLink from '../LeftMenuLink';
import Dropdown from './Dropdown';
const LeftMenuSubList = ({
isEditable,
isFirstItem,
isSearching,
links,
name,
onClickEdit,
}) => {
const LeftMenuSubList = ({ isEditable, isFirstItem, isSearching, links, name, onClickEdit }) => {
const [collapse, setCollapse] = useState(isFirstItem);
const { formatMessage } = useGlobalContext();
const toggle = () => {
setCollapse(!collapse);
};
const getLabel = message => {
if (isObject(message) && message.id) {
return formatMessage({
...message,
defaultMessage: message.defaultMessage || message.id,
});
}
return message;
};
useEffect(() => {
if (isSearching) {
setCollapse(true);
@ -32,10 +38,7 @@ const LeftMenuSubList = ({
return (
links.length > 0 && (
<Dropdown>
<button
onClick={toggle}
className={`editable ${collapse ? 'is-open' : ''}`}
>
<button onClick={toggle} className={`editable ${collapse ? 'is-open' : ''}`}>
{name}
{isEditable && (
<FontAwesomeIcon
@ -53,9 +56,7 @@ const LeftMenuSubList = ({
return (
<li key={name}>
<LeftMenuLink {...link}>
{useFormattedMessage(title)}
</LeftMenuLink>
<LeftMenuLink {...link}>{getLabel(title)}</LeftMenuLink>
</li>
);
})}

View File

@ -4,6 +4,7 @@
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import styled, { keyframes } from 'styled-components';
const spin = keyframes`
@ -20,8 +21,8 @@ const Loader = styled.div`
justify-content: space-around;
width: 100%;
> div {
width: 26px;
height: 26px;
width: ${({ small }) => (small ? '11px' : '26px')};
height: ${({ small }) => (small ? '11px' : '26px')};
border: 4px solid #f3f3f3;
border-top: 4px solid #555555 !important;
border-radius: 50%;
@ -29,10 +30,18 @@ const Loader = styled.div`
}
`;
const LoadingIndicator = () => (
<Loader>
const LoadingIndicator = ({ small }) => (
<Loader small={small}>
<div />
</Loader>
);
LoadingIndicator.propTypes = {
small: PropTypes.bool,
};
LoadingIndicator.defaultProps = {
small: false,
};
export default LoadingIndicator;

View File

@ -1,20 +1,21 @@
import styled from 'styled-components';
const Option = styled.div`
display: flex;
justify-content: space-between;
align-items: baseline;
padding: 0.5rem 1rem;
font-size: 1.5rem;
line-height: 3rem;
cursor: pointer;
&:hover {
background-color: #e4f0fc;
.right-label {
display: block;
}
}
cursor: pointer;
line-height: 2.6rem;
font-size: 1.5rem;
padding: 5px;
display: flex;
justify-content: space-between;
.right-label {
display: none;
display: block;
}
`;

View File

@ -1,12 +1,12 @@
import styled from 'styled-components';
const OptionsTitle = styled.div`
line-height: 2.1rem;
padding: 0.7rem 1rem;
font-size: 1.2rem;
padding: 5px;
font-weight: bold;
line-height: 2.1rem;
text-transform: uppercase;
color: ${({ theme }) => theme.main.colors.grayLight};
border-bottom: 1px solid ${({ theme }) => theme.main.colors.border};
color: #9ea7b8;
`;
export default OptionsTitle;

View File

@ -1,9 +1,10 @@
import styled from 'styled-components';
const RightOptionLabel = styled.div`
color: ${({ theme }) => theme.main.colors.strapi.blue};
color: #007dff;
text-transform: uppercase;
font-weight: bold;
font-size: 1.1rem;
`;
export default RightOptionLabel;

View File

@ -14,7 +14,6 @@ const Options = ({ options, title }) => (
{options.map(option => (
<Option key={option.id} onClick={option.onClick}>
<div>{option.label}</div>
<FormattedMessage id={getTrad('components.uid.apply')}>
{msg => <RightOptionLabel className="right-label">{msg}</RightOptionLabel>}
</FormattedMessage>

View File

@ -7,7 +7,7 @@ const wrapper = styled.div`
border: 1px solid ${props => props.theme.main.colors.border};
border-radius: 2px;
background-color: white;
z-index: 10;
z-index: 11;
`;
export default wrapper;

View File

@ -12,6 +12,7 @@ import getTrad from '../../utils/getTrad';
const RightContentLabel = styled.div`
padding: 0 5px;
text-transform: capitalize;
font-size: 1.3rem;
color: ${({ theme, color }) => theme.main.colors[color]};
`;
@ -41,7 +42,7 @@ const RightLabel = ({ label, availability }) => {
</>
) : (
<>
<Remove fill="#ff203c" width="12px" height="12px" />
<Remove fill="#ff203c" width="9px" height="9px" />
<RightContentLabel color="red">
{formatMessage({
id: getTrad('components.uid.unavailable'),

View File

@ -0,0 +1,9 @@
import styled from 'styled-components';
const SubLabel = styled.p`
padding-top: 10px;
line-height: normal;
font-size: 1.3rem;
`;
export default SubLabel;

View File

@ -0,0 +1,8 @@
import styled from 'styled-components';
const Wrapper = styled.div`
position: relative;
padding-bottom: 23px;
`;
export default Wrapper;

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState, useRef } from 'react';
import PropTypes from 'prop-types';
import { Sync } from '@buffetjs/icons';
import { ErrorMessage as BaseErrorMessage } from '@buffetjs/styles';
import { ErrorMessage, Description } from '@buffetjs/styles';
import { Label, Error } from '@buffetjs/core';
import { useDebounce, useClickAwayListener } from '@buffetjs/hooks';
import styled from 'styled-components';
@ -17,18 +17,13 @@ import Options from './Options';
import RegenerateButton from './RegenerateButton';
import RightContent from './RightContent';
import Input from './InputUID';
import Wrapper from './Wrapper';
import SubLabel from './SubLabel';
import UID_REGEX from './regex';
// There is no need to create additional files for those little components.
const Wrapper = styled.div`
position: relative;
padding-bottom: 23px;
`;
const InputContainer = styled.div`
position: relative;
`;
const ErrorMessage = styled(BaseErrorMessage)`
padding-top: 10px;
`;
const Name = styled(Label)`
display: block;
text-transform: capitalize;
@ -43,12 +38,15 @@ const Name = styled(Label)`
const InputUID = ({
attribute,
contentTypeUID,
description,
error: inputError,
name,
onChange,
required,
validations,
value,
editable,
...inputProps
}) => {
const { modifiedData, initialData } = useDataManager();
const [isLoading, setIsLoading] = useState(false);
@ -92,7 +90,7 @@ const InputUID = ({
body: {
contentTypeUID,
field: name,
value: value || null,
value: value ? value.trim() : null,
},
});
setAvailability(data);
@ -115,7 +113,11 @@ const InputUID = ({
}, []);
useEffect(() => {
if (debouncedValue && debouncedValue !== initialValue) {
if (
debouncedValue &&
debouncedValue.trim().match(UID_REGEX) &&
debouncedValue !== initialValue
) {
checkAvailability();
}
if (!debouncedValue) {
@ -187,7 +189,12 @@ const InputUID = ({
};
return (
<Error name={name} inputError={inputError} type="text" validations={validations}>
<Error
name={name}
inputError={inputError}
type="text"
validations={{ ...validations, regex: UID_REGEX }}
>
{({ canCheck, onBlur, error, dispatch }) => {
const hasError = error && error !== null;
@ -196,6 +203,8 @@ const InputUID = ({
<Name htmlFor={name}>{name}</Name>
<InputContainer>
<Input
{...inputProps}
editable={editable}
error={hasError}
onFocus={handleFocus}
name={name}
@ -207,17 +216,19 @@ const InputUID = ({
/>
<RightContent>
<RightLabel availability={availability} label={label} />
<RegenerateButton
onMouseEnter={handleGenerateMouseEnter}
onMouseLeave={handleGenerateMouseLeave}
onClick={generateUid.current}
>
{isLoading ? (
<LoadingIndicator />
) : (
<Sync fill={label ? '#007EFF' : '#B5B7BB'} width="15px" height="15px" />
)}
</RegenerateButton>
{editable && (
<RegenerateButton
onMouseEnter={handleGenerateMouseEnter}
onMouseLeave={handleGenerateMouseLeave}
onClick={generateUid.current}
>
{isLoading ? (
<LoadingIndicator small />
) : (
<Sync fill={label ? '#007EFF' : '#B5B7BB'} width="11px" height="11px" />
)}
</RegenerateButton>
)}
</RightContent>
{availability && availability.suggestion && isSuggestionOpen && (
<FormattedMessage id={`${pluginId}.components.uid.suggested`}>
@ -236,7 +247,8 @@ const InputUID = ({
</FormattedMessage>
)}
</InputContainer>
{hasError && <ErrorMessage>{error}</ErrorMessage>}
{!hasError && description && <SubLabel as={Description}>{description}</SubLabel>}
{hasError && <SubLabel as={ErrorMessage}>{error}</SubLabel>}
</Wrapper>
);
}}
@ -247,6 +259,8 @@ const InputUID = ({
InputUID.propTypes = {
attribute: PropTypes.object.isRequired,
contentTypeUID: PropTypes.string.isRequired,
description: PropTypes.string,
editable: PropTypes.bool,
error: PropTypes.string,
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
@ -256,6 +270,8 @@ InputUID.propTypes = {
};
InputUID.defaultProps = {
description: '',
editable: false,
error: null,
required: false,
validations: {},

View File

@ -0,0 +1,3 @@
const UID_REGEX = new RegExp(/^[A-Za-z0-9-_.~]*$/);
export default UID_REGEX;

View File

@ -3,7 +3,7 @@ import styled, { css } from 'styled-components';
/* eslint-disable */
const SelectWrapper = styled.div`
min-width: ${({ isFullScreen }) => (isFullScreen ? '161px' : '115px')}
min-width: ${({ isFullScreen }) => (isFullScreen ? '161px' : '115px')};
margin-left: 15px;
> select {
${({ isFullScreen }) => {

View File

@ -11,14 +11,7 @@ import Wrapper from './Wrapper';
/* eslint-disable jsx-a11y/control-has-associated-label */
const ComponentIconPicker = ({
error,
isCreating,
label,
name,
onChange,
value,
}) => {
const ComponentIconPicker = ({ error, isCreating, label, name, onChange, value }) => {
const { allIcons, allComponentsIconAlreadyTaken } = useDataManager();
const initialIcons = allIcons.filter(ico => {
if (isCreating) {
@ -26,9 +19,7 @@ const ComponentIconPicker = ({
}
// Edition
return !allComponentsIconAlreadyTaken
.filter(icon => icon !== originalIcon)
.includes(ico);
return !allComponentsIconAlreadyTaken.filter(icon => icon !== originalIcon).includes(ico);
});
const ref = createRef();
const [originalIcon] = useState(value);
@ -85,12 +76,10 @@ const ComponentIconPicker = ({
ref={ref}
onChange={({ target: { value } }) => {
setSearch(value);
setIcons(() =>
initialIcons.filter(icon => icon.includes(value))
);
setIcons(() => initialIcons.filter(icon => icon.includes(value)));
}}
value={search}
placeholder="search…"
placeholder="Search…"
/>
<button
onClick={() => {
@ -130,11 +119,7 @@ const ComponentIconPicker = ({
);
}}
</AutoSizer>
{error && (
<ErrorMessage style={{ marginTop: 5, marginBottom: 16 }}>
{error}
</ErrorMessage>
)}
{error && <ErrorMessage style={{ marginTop: 5, marginBottom: 16 }}>{error}</ErrorMessage>}
</Wrapper>
);
};

View File

@ -420,7 +420,7 @@ const DataManagerProvider = ({ allIcons, children }) => {
emitEvent('didNotSaveComponent');
}
console.error({ err });
strapi.notification.error('notification.error');
strapi.notification.error(err.response.payload.error || 'notification.error');
}
};

View File

@ -11,7 +11,6 @@ const getAttributes = (dataTarget = '', targetUid, nestedComponents) => {
'media',
'boolean',
'json',
'uid',
'relation',
],
];
@ -23,6 +22,7 @@ const getAttributes = (dataTarget = '', targetUid, nestedComponents) => {
const items = defaultAttributes.slice();
if (isPickingAttributeForAContentType) {
items[0].push('uid');
items.push(['component', 'dynamiczone']);
}

View File

@ -716,28 +716,40 @@ const forms = {
.filter(key => ['string', 'text'].includes(attributes[key].type))
.map(key => ({ id: key, value: key }));
items[0].push({
label: {
id: getTrad('modalForm.attribute.target-field'),
},
name: 'targetField',
type: 'select',
options: [{ id: getTrad('none'), value: '' }, ...options].map((option, index) => (
// eslint-disable-next-line react/no-array-index-key
<Fragment key={index}>
{index === 0 ? (
<FormattedMessage id={option.id}>
{msg => <option value={option.value}>{msg}</option>}
</FormattedMessage>
) : (
<option value={option.value}>{option.value}</option>
)}
</Fragment>
)),
validations: {
required: true,
},
});
return {
items: [
[
{
...fields.name,
placeholder: {
id: getTrad('modalForm.attribute.form.base.name.placeholder'),
},
},
{
label: {
id: getTrad('modalForm.attribute.target-field'),
},
name: 'targetField',
type: 'select',
options: [{ id: getTrad('none'), value: '' }, ...options].map((option, index) => (
// eslint-disable-next-line react/no-array-index-key
<Fragment key={index}>
{index === 0 ? (
<FormattedMessage id={option.id}>
{msg => <option value={option.value}>{msg}</option>}
</FormattedMessage>
) : (
<option value={option.value}>{option.value}</option>
)}
</Fragment>
)),
validations: {
required: true,
},
},
],
],
};
}
return {

View File

@ -28,7 +28,7 @@
"attribute.text": "Text",
"attribute.text.description": "Krátký nebo delší text",
"attribute.time": "Čas",
"attribute.uid": "Uid",
"attribute.uid": "UID",
"attribute.uid.description": "Unikátní identifikátor",
"button.attributes.add.another": "Přidat další pole",
"button.component.add": "Přidat komponent",

View File

@ -30,7 +30,7 @@
"attribute.time": "Time",
"attribute.timestamp": "Timestamp",
"attribute.uid.description": "Unique identifier",
"attribute.uid": "Uid",
"attribute.uid": "UID",
"button.attributes.add.another": "Add another field",
"button.component.add": "Add a component",
"button.component.create": "Create new component",
@ -100,6 +100,7 @@
"form.button.add-first-field-to-created-component": "Add first field to the component",
"form.button.add.field.to.component": "Add another field to this component",
"form.button.add.field.to.collectionType": "Add another field to this collection type",
"form.button.add.field.to.contentType ": "Add another field to this content type",
"form.button.add.field.to.singleType": "Add another field to this single type",
"form.button.cancel": "Cancel",
"form.button.configure-component": "Configure the component",
@ -113,7 +114,7 @@
"form.button.single-type.description": "Best for single instance like about us, homepage, etc.",
"from": "from",
"injected-components.content-manager.edit-settings-view.link.components": "Edit the component",
"injected-components.content-manager.edit-settings-view.link.content-types": "Edit the collection type",
"injected-components.content-manager.edit-settings-view.link.content-types": "Edit the content type",
"menu.section.components.name.plural": "Components",
"menu.section.components.name.singular": "Component",
"menu.section.models.name.plural": "Collection Types",
@ -123,6 +124,7 @@
"modalForm.attribute.target-field": "Attached field",
"modalForm.attribute.form.base.name.description": "No space is allowed for the name of the attribute",
"modalForm.attribute.form.base.name": "Name",
"modalForm.attribute.form.base.name.placeholder": "e.g. Slug, SEO URL, Canonical URL",
"modalForm.attribute.text.type-selection": "Type",
"modalForm.attributes.select-component": "Select a component",
"modalForm.attributes.select-components": "Select the components",

View File

@ -36,6 +36,7 @@
"form.attribute.settings.default": "Valeur par défault",
"form.button.add.field.to.component": "Ajouter un nouveau champ à ce composant",
"form.button.add.field.to.collectionType": "Ajouter un nouveau champ à cette collection",
"form.button.add.field.to.contentType ": "Ajouter un nouveau champ à cette content type",
"form.button.add.field.to.singleType": "Ajouter un nouveau champ à ce single type",
"form.button.cancel": "Annuler",
"form.button.configure-view": "Configurer la vue",
@ -44,6 +45,8 @@
"form.button.finish": "Terminer",
"form.button.delete": "Supprimer",
"from": "de",
"injected-components.content-manager.edit-settings-view.link.content-types": "Modifier le content type",
"injected-components.content-manager.edit-settings-view.link.components": "Modifier le composant",
"menu.section.components.name.plural": "Composants",
"menu.section.components.name.singular": "Composant",
"menu.section.models.name.plural": "Collections",
@ -52,6 +55,7 @@
"menu.section.single-types.name.singular": "Single Type",
"modalForm.attribute.target-field": "Champ associé",
"modalForm.attribute.target-field.none": "Aucun",
"modalForm.attribute.form.base.name.placeholder": "ex : Slug, URL SEO, URL Canonique",
"modalForm.singleType.header-create": "Créer un single type",
"none": "Aucun",
"button.single-types.create": "Créer un single type",

View File

@ -68,7 +68,7 @@
"attribute.richtext.description": "Edytor tekstu z możliwością formatowania",
"attribute.text.description": "Krótki lub długi tekst jak tytuł lub opis",
"attribute.time": "Czas",
"attribute.uid": "Uid",
"attribute.uid": "UID",
"attribute.uid.description": "Unikalny identyfikator",
"button.attributes.add.another": "Dodaj kolejne pole",
"button.component.add": "Dodaj komponent",

View File

@ -28,7 +28,7 @@
"attribute.text": "Text",
"attribute.text.description": "Простой текст для заголовка или описания",
"attribute.time": "Time",
"attribute.uid": "Uid",
"attribute.uid": "UID",
"attribute.uid.description": "Уникальный идентификатор",
"button.attributes.add.another": "Ещё поле",
"button.component.add": "Добавить компонент",

View File

@ -28,7 +28,7 @@
"attribute.text": "Text",
"attribute.text.description": "Krátky alebo dlhší text",
"attribute.time": "Čas",
"attribute.uid": "Uid",
"attribute.uid": "UID",
"attribute.uid.description": "Unikátny identifikátor",
"button.attributes.add.another": "Pridať ďalšie políčko",
"button.component.add": "Pridať komponent",

View File

@ -28,7 +28,7 @@
"attribute.text": "文本",
"attribute.text.description": "较短或较长的文字,例如标题或说明",
"attribute.time": "时间",
"attribute.uid": "Uid",
"attribute.uid": "UID",
"attribute.uid.description": "唯一标识符",
"button.attributes.add.another": "添加一个新字段",
"button.component.add": "添加组件",