@mirrormedia/lilith-draft-editor
Version:
## Installation
483 lines (428 loc) • 16.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ImageSelector = ImageSelector;
var _react = _interopRequireWildcard(require("react"));
var _debounce = _interopRequireDefault(require("lodash/debounce"));
var _styledComponents = _interopRequireWildcard(require("styled-components"));
var _fields = require("@keystone-ui/fields");
var _modals = require("@keystone-ui/modals");
var _apollo = require("@keystone-6/core/admin-ui/apollo");
var _alignSelector = require("./align-selector");
var _searchBox = require("./search-box");
var _pagination = require("./pagination");
var _button = require("@keystone-ui/button");
var _imageUploader = require("./image-uploader");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
const imagesQuery = (0, _apollo.gql)`
query Photos($searchText: String!, $take: Int, $skip: Int) {
photosCount(where: { name: { contains: $searchText } })
photos(
where: { name: { contains: $searchText } }
orderBy: { id: desc }
take: $take
skip: $skip
) {
id
name
imageFile {
url
width
height
}
resized {
original
w480
w800
w1200
w1600
w2400
}
resizedWebp {
original
w480
w800
w1200
w1600
w2400
}
}
}
`;
const _ = {
debounce: _debounce.default
};
const GlobalStyle = (0, _styledComponents.createGlobalStyle)`
form {
@media (max-width: 575px) {
width: 100vw !important;
}
}
`;
const ImageSearchBox = (0, _styledComponents.default)(_searchBox.SearchBox)`
margin-top: 10px;
`;
const CustomButton = (0, _styledComponents.default)(_button.Button)`
margin-top: 10px;
`;
const ImageSelectionWrapper = _styledComponents.default.div`
overflow: auto;
margin-top: 10px;
`;
const ImageBlockMetaWrapper = _styledComponents.default.div``;
const ImageGridsWrapper = _styledComponents.default.div`
display: flex;
flex-wrap: wrap;
overflow: auto;
margin-top: 5px;
`;
const ImageGridWrapper = _styledComponents.default.div`
width: 33.3333%;
cursor: pointer;
padding: 0 10px 10px;
`;
const ImageMetaGridsWrapper = _styledComponents.default.div`
display: flex;
flex-wrap: wrap;
overflow: auto;
`;
const ImageMetaGridWrapper = _styledComponents.default.div`
width: 100%;
cursor: pointer;
padding: 0 10px 10px;
`;
const Image = _styledComponents.default.img`
display: block;
width: 100%;
aspect-ratio: 2;
object-fit: cover;
`;
const Label = _styledComponents.default.label`
display: block;
margin: 10px 0;
font-weight: 600;
`;
const StyledTextInput = (0, _styledComponents.default)(_fields.TextInput)`
width: 100%;
`;
const SeparationLine = _styledComponents.default.div`
border: #e1e5e9 1px solid;
margin-top: 10px;
margin-bottom: 10px;
`;
const ImageSelected = _styledComponents.default.div`
height: 1.4rem;
`;
const ErrorWrapper = _styledComponents.default.div`
& * {
margin: 0;
}
`;
const ImageName = _styledComponents.default.p`
text-align: center;
`;
function ImageGrids(props) {
const {
images,
selected,
onSelect
} = props;
return /*#__PURE__*/_react.default.createElement(ImageGridsWrapper, null, images.map(image => {
return /*#__PURE__*/_react.default.createElement(ImageGrid, {
key: image.id,
isSelected: !!(selected !== null && selected !== void 0 && selected.find(selectedImage => selectedImage.id === image.id)),
onSelect: () => onSelect(image),
image: image
});
}));
}
function ImageGrid(props) {
var _image$resized;
const {
image,
onSelect,
isSelected
} = props;
return /*#__PURE__*/_react.default.createElement(ImageGridWrapper, {
key: image === null || image === void 0 ? void 0 : image.id,
onClick: () => onSelect(image)
}, /*#__PURE__*/_react.default.createElement(ImageSelected, null, isSelected ? /*#__PURE__*/_react.default.createElement("i", {
className: "fas fa-check-circle"
}) : null), /*#__PURE__*/_react.default.createElement(Image, {
src: image === null || image === void 0 ? void 0 : (_image$resized = image.resized) === null || _image$resized === void 0 ? void 0 : _image$resized.w800,
onError: e => {
var _image$imageFile;
return e.currentTarget.src = image === null || image === void 0 ? void 0 : (_image$imageFile = image.imageFile) === null || _image$imageFile === void 0 ? void 0 : _image$imageFile.url;
}
}));
}
function ImageMetaGrids(props) {
const {
imageMetas,
onChange,
enableCaption,
enableUrl
} = props;
return /*#__PURE__*/_react.default.createElement(ImageMetaGridsWrapper, null, imageMetas.map(imageMeta => {
var _imageMeta$image;
return /*#__PURE__*/_react.default.createElement(ImageMetaGrid, {
key: imageMeta === null || imageMeta === void 0 ? void 0 : (_imageMeta$image = imageMeta.image) === null || _imageMeta$image === void 0 ? void 0 : _imageMeta$image.id,
imageMeta: imageMeta,
enableCaption: enableCaption,
enableUrl: enableUrl,
onChange: onChange
});
}));
}
function ImageMetaGrid(props) {
var _image$resized2;
const {
imageMeta,
enableCaption,
enableUrl,
onChange
} = props;
const {
image,
desc,
url
} = imageMeta;
return /*#__PURE__*/_react.default.createElement(ImageMetaGridWrapper, null, /*#__PURE__*/_react.default.createElement(Image, {
src: image === null || image === void 0 ? void 0 : (_image$resized2 = image.resized) === null || _image$resized2 === void 0 ? void 0 : _image$resized2.w800,
onError: e => {
var _image$imageFile2;
return e.currentTarget.src = image === null || image === void 0 ? void 0 : (_image$imageFile2 = image.imageFile) === null || _image$imageFile2 === void 0 ? void 0 : _image$imageFile2.url;
}
}), /*#__PURE__*/_react.default.createElement(ImageName, null, image === null || image === void 0 ? void 0 : image.name), enableCaption && /*#__PURE__*/_react.default.createElement(_react.Fragment, null, /*#__PURE__*/_react.default.createElement(Label, {
htmlFor: "caption"
}, "Image Caption:"), /*#__PURE__*/_react.default.createElement(StyledTextInput, {
id: "caption",
type: "text",
placeholder: image === null || image === void 0 ? void 0 : image.name,
defaultValue: desc,
onChange: _.debounce(e => {
onChange({
image,
desc: e.target.value,
url
});
})
})), enableUrl && /*#__PURE__*/_react.default.createElement(_react.Fragment, null, /*#__PURE__*/_react.default.createElement(Label, {
htmlFor: "url"
}, "Url:"), /*#__PURE__*/_react.default.createElement(StyledTextInput, {
id: "url",
type: "text",
placeholder: "(Optional)",
defaultValue: url,
onChange: _.debounce(e => {
onChange({
image,
desc,
url: e.target.value
});
})
})));
}
function DelayInput(props) {
const {
delay,
onChange
} = props;
return /*#__PURE__*/_react.default.createElement(_react.Fragment, null, /*#__PURE__*/_react.default.createElement(Label, null, "Slideshow delay:"), /*#__PURE__*/_react.default.createElement(_fields.TextInput, {
type: "number",
placeholder: "\u8ACB\u8F38\u5165\u81EA\u52D5\u5207\u63DB\u79D2\u6578",
step: "0.5",
min: "1",
value: delay,
onChange: e => {
onChange(e.target.value);
}
}));
}
function ImageSelector(props) {
const {
enableMultiSelect = false,
enableCaption = false,
enableUrl = false,
enableAlignment = false,
enableDelay = false,
onChange,
initialSelected = [],
initialAlign,
initialDelay
} = props;
const [queryImages, {
loading,
error,
data: {
photos: images = [],
photosCount: imagesCount = 0
} = {}
}] = (0, _apollo.useLazyQuery)(imagesQuery, {
fetchPolicy: 'no-cache'
});
const [currentPage, setCurrentPage] = (0, _react.useState)(0); // page starts with 1, 0 is used to detect initialization
const [searchText, setSearchText] = (0, _react.useState)('');
const [selected, setSelected] = (0, _react.useState)(initialSelected);
const [delay, setDelay] = (0, _react.useState)(initialDelay ?? '5');
const [align, setAlign] = (0, _react.useState)(initialAlign);
const [showImageUploader, setShowImageUploader] = (0, _react.useState)(false);
const contentWrapperRef = (0, _react.useRef)(null);
const pageSize = 18;
const options = [{
value: undefined,
label: 'default',
isDisabled: false
}, {
value: 'left',
label: 'left',
isDisabled: false
}, {
value: 'right',
label: 'right',
isDisabled: false
}];
const onSave = () => {
let adjustedDelay = +delay;
adjustedDelay = adjustedDelay < 1 ? 1 : adjustedDelay;
onChange(selected, align, adjustedDelay);
};
const onCancel = () => {
onChange([]);
};
const onSearchBoxChange = async searchInput => {
setSearchText(searchInput);
setCurrentPage(1);
};
const onDealyChange = delay => {
setDelay(delay);
};
const onAlignSelectChange = align => {
setAlign(align);
};
const onAlignSelectOpen = () => {
var _contentWrapperRef$cu;
const scrollWrapper = (_contentWrapperRef$cu = contentWrapperRef.current) === null || _contentWrapperRef$cu === void 0 ? void 0 : _contentWrapperRef$cu.parentElement;
if (scrollWrapper) {
scrollWrapper.scrollTop = scrollWrapper.scrollHeight;
}
};
const onImageUploaderChange = images => {
setSelected(prev => prev.concat(images.map(image => ({
image,
desc: '',
url: ''
}))));
setShowImageUploader(false);
};
const onImageMetaChange = imageEntityWithMeta => {
if (enableMultiSelect) {
const foundIndex = selected.findIndex(ele => {
var _ele$image, _imageEntityWithMeta$;
return (ele === null || ele === void 0 ? void 0 : (_ele$image = ele.image) === null || _ele$image === void 0 ? void 0 : _ele$image.id) === (imageEntityWithMeta === null || imageEntityWithMeta === void 0 ? void 0 : (_imageEntityWithMeta$ = imageEntityWithMeta.image) === null || _imageEntityWithMeta$ === void 0 ? void 0 : _imageEntityWithMeta$.id);
});
if (foundIndex !== -1) {
selected[foundIndex] = imageEntityWithMeta;
setSelected(selected);
}
return;
}
setSelected([imageEntityWithMeta]);
};
const onImagesGridSelect = imageEntity => {
setSelected(selected => {
const filterdSelected = selected.filter(ele => {
var _ele$image2;
return ((_ele$image2 = ele.image) === null || _ele$image2 === void 0 ? void 0 : _ele$image2.id) !== imageEntity.id;
}); // deselect the image
if (filterdSelected.length !== selected.length) {
return filterdSelected;
} // add new selected one
if (enableMultiSelect) {
return selected.concat([{
image: imageEntity,
desc: ''
}]);
} // single select
return [{
image: imageEntity,
desc: ''
}];
});
};
const selectedImages = selected.map(ele => {
return ele.image;
});
(0, _react.useEffect)(() => {
if (currentPage !== 0) {
queryImages({
variables: {
searchText: searchText,
skip: (currentPage - 1) * pageSize,
take: pageSize
}
});
}
}, [currentPage, searchText]);
let searchResult = /*#__PURE__*/_react.default.createElement(_react.Fragment, null, /*#__PURE__*/_react.default.createElement(ImageGrids, {
images: images,
selected: selectedImages,
onSelect: onImagesGridSelect
}), /*#__PURE__*/_react.default.createElement(_pagination.Pagination, {
currentPage: currentPage,
total: imagesCount,
pageSize: pageSize,
onChange: pageIndex => {
setCurrentPage(pageIndex);
}
}));
if (loading) {
searchResult = /*#__PURE__*/_react.default.createElement("p", null, "searching...");
}
if (error) {
var _imagesQuery$loc, _imagesQuery$loc$sour;
searchResult = /*#__PURE__*/_react.default.createElement(ErrorWrapper, null, /*#__PURE__*/_react.default.createElement("h3", null, "Errors occurs in the `images` query"), /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("br", null), /*#__PURE__*/_react.default.createElement("b", null, "Message:"), /*#__PURE__*/_react.default.createElement("div", null, error.message), /*#__PURE__*/_react.default.createElement("br", null), /*#__PURE__*/_react.default.createElement("b", null, "Stack:"), /*#__PURE__*/_react.default.createElement("div", null, error.stack), /*#__PURE__*/_react.default.createElement("br", null), /*#__PURE__*/_react.default.createElement("b", null, "Query:"), /*#__PURE__*/_react.default.createElement("pre", null, imagesQuery === null || imagesQuery === void 0 ? void 0 : (_imagesQuery$loc = imagesQuery.loc) === null || _imagesQuery$loc === void 0 ? void 0 : (_imagesQuery$loc$sour = _imagesQuery$loc.source) === null || _imagesQuery$loc$sour === void 0 ? void 0 : _imagesQuery$loc$sour.body)));
}
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(GlobalStyle, null), /*#__PURE__*/_react.default.createElement(_modals.DrawerController, {
isOpen: true
}, /*#__PURE__*/_react.default.createElement(_modals.Drawer, {
title: "Select images",
actions: {
cancel: {
label: 'Cancel',
action: onCancel
},
confirm: {
label: 'Confirm',
action: onSave
}
},
width: "narrow"
}, /*#__PURE__*/_react.default.createElement("div", {
ref: contentWrapperRef
}, /*#__PURE__*/_react.default.createElement(CustomButton, {
onClick: () => setShowImageUploader(true)
}, "\u4E0A\u50B3\u5716\u7247"), /*#__PURE__*/_react.default.createElement(ImageSearchBox, {
onChange: onSearchBoxChange
}), /*#__PURE__*/_react.default.createElement(ImageSelectionWrapper, null, /*#__PURE__*/_react.default.createElement("div", null, searchResult), !!selected.length && /*#__PURE__*/_react.default.createElement(SeparationLine, null), /*#__PURE__*/_react.default.createElement(ImageMetaGrids, {
imageMetas: selected,
onChange: onImageMetaChange,
enableCaption: enableCaption,
enableUrl: enableUrl
})), /*#__PURE__*/_react.default.createElement(ImageBlockMetaWrapper, null, (enableDelay || enableAlignment) && /*#__PURE__*/_react.default.createElement(SeparationLine, null), enableDelay && /*#__PURE__*/_react.default.createElement(DelayInput, {
delay: delay,
onChange: onDealyChange
}), enableAlignment && /*#__PURE__*/_react.default.createElement(_alignSelector.AlignSelector // @ts-ignore: align could be undefined
, {
align: align // @ts-ignore: option with undefined value
,
options: options,
onChange: onAlignSelectChange,
onOpen: onAlignSelectOpen
}))))), showImageUploader && /*#__PURE__*/_react.default.createElement(_imageUploader.ImageUploader, {
onChange: onImageUploaderChange
}));
}