UNPKG

@mirrormedia/lilith-draft-editor

Version:
463 lines (417 loc) 15.4 kB
"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 Images($searchText: String!, $take: Int, $skip: Int) { imagesCount(where: { name: { contains: $searchText } }) images( where: { name: { contains: $searchText } } orderBy: { id: desc } take: $take skip: $skip ) { id name file { 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, _image$file; const { image, onSelect, isSelected } = props; const initialSrc = (image === null || image === void 0 ? void 0 : (_image$resized = image.resized) === null || _image$resized === void 0 ? void 0 : _image$resized.w800) || (image === null || image === void 0 ? void 0 : (_image$file = image.file) === null || _image$file === void 0 ? void 0 : _image$file.url); 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", style: { color: '#007bff' } }) : null), /*#__PURE__*/_react.default.createElement(Image, { src: initialSrc, onError: e => { var _image$file2; if (image !== null && image !== void 0 && (_image$file2 = image.file) !== null && _image$file2 !== void 0 && _image$file2.url && e.currentTarget.src !== image.file.url) { e.currentTarget.src = image.file.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, _image$file3; const { imageMeta, enableCaption, enableUrl, onChange } = props; const { image, desc, url } = imageMeta; const src = (image === null || image === void 0 ? void 0 : (_image$resized2 = image.resized) === null || _image$resized2 === void 0 ? void 0 : _image$resized2.w800) || (image === null || image === void 0 ? void 0 : (_image$file3 = image.file) === null || _image$file3 === void 0 ? void 0 : _image$file3.url); return /*#__PURE__*/_react.default.createElement(ImageMetaGridWrapper, null, /*#__PURE__*/_react.default.createElement(Image, { src: src, onError: e => { var _image$file4; if (image !== null && image !== void 0 && (_image$file4 = image.file) !== null && _image$file4 !== void 0 && _image$file4.url && e.currentTarget.src !== image.file.url) { e.currentTarget.src = image.file.url; } } }), /*#__PURE__*/_react.default.createElement(ImageName, { style: { textAlign: 'left' } }, 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(_fields.TextInput, { 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 }); }, 300) })), enableUrl && /*#__PURE__*/_react.default.createElement(_react.Fragment, null, /*#__PURE__*/_react.default.createElement(Label, { htmlFor: "url" }, "Url:"), /*#__PURE__*/_react.default.createElement(_fields.TextInput, { id: "url", type: "text", placeholder: "(Optional)", defaultValue: url, onChange: _.debounce(e => { onChange({ image, desc, url: e.target.value }); }, 300) }))); } 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: { images = [], imagesCount = 0 } = {} }] = (0, _apollo.useLazyQuery)(imagesQuery, { fetchPolicy: 'no-cache' }); const [currentPage, setCurrentPage] = (0, _react.useState)(0); const [searchText, setSearchText] = (0, _react.useState)(''); const [selected, setSelected] = (0, _react.useState)(initialSelected); const [delay, setDelay] = (0, _react.useState)((initialDelay === null || initialDelay === void 0 ? void 0 : initialDelay.toString()) ?? '5'); const [align, setAlign] = (0, _react.useState)(initialAlign); const [showImageUploader, setShowImageUploader] = (0, _react.useState)(false); const contentWrapperRef = (0, _react.useRef)(null); const pageSize = 18; // Data Fetching Logic (0, _react.useEffect)(() => { if (currentPage !== 0) { queryImages({ variables: { searchText, skip: (currentPage - 1) * pageSize, take: pageSize } }); } }, [currentPage, searchText, queryImages]); // Selection Handler const onImagesGridSelect = imageEntity => { setSelected(prev => { const isSelected = prev.find(ele => { var _ele$image; return ((_ele$image = ele.image) === null || _ele$image === void 0 ? void 0 : _ele$image.id) === imageEntity.id; }); if (isSelected) { return prev.filter(ele => { var _ele$image2; return ((_ele$image2 = ele.image) === null || _ele$image2 === void 0 ? void 0 : _ele$image2.id) !== imageEntity.id; }); } const newItem = { image: imageEntity, desc: '', url: '' }; if (enableMultiSelect) { return [...prev, newItem]; } return [newItem]; }); }; // 3. Metadata Handler const onImageMetaChange = updatedItem => { setSelected(prev => prev.map(item => item.image.id === updatedItem.image.id ? updatedItem : item)); }; const onSave = () => { const adjustedDelay = Math.max(1, parseFloat(delay) || 1); onChange(selected, align, adjustedDelay); }; const onCancel = () => { onChange([]); }; const onSearchBoxChange = searchInput => { setSearchText(searchInput); setCurrentPage(1); }; const onImageUploaderChange = uploadedImages => { const newItems = uploadedImages.map(img => ({ image: img, desc: '', url: '' })); setSelected(prev => [...prev, ...newItems]); setShowImageUploader(false); }; let searchResult = /*#__PURE__*/_react.default.createElement(_react.Fragment, null, /*#__PURE__*/_react.default.createElement(ImageGrids, { images: images, selected: selected.map(s => s.image), onSelect: onImagesGridSelect }), /*#__PURE__*/_react.default.createElement(_pagination.Pagination, { currentPage: currentPage, total: imagesCount, pageSize: pageSize, onChange: page => setCurrentPage(page) })); if (loading) searchResult = /*#__PURE__*/_react.default.createElement("p", null, "searching..."); if (error) { searchResult = /*#__PURE__*/_react.default.createElement(ErrorWrapper, null, /*#__PURE__*/_react.default.createElement("h3", null, "Errors in query"), /*#__PURE__*/_react.default.createElement("div", null, error.message)); } 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(ImageMetaGridsWrapper, null, selected.map(item => /*#__PURE__*/_react.default.createElement(ImageMetaGrid, { key: item.image.id, imageMeta: item, enableCaption: enableCaption, enableUrl: enableUrl, onChange: onImageMetaChange })))), /*#__PURE__*/_react.default.createElement("div", { style: { marginTop: '20px' } }, (enableDelay || enableAlignment) && /*#__PURE__*/_react.default.createElement(SeparationLine, null), enableDelay && /*#__PURE__*/_react.default.createElement(_react.Fragment, null, /*#__PURE__*/_react.default.createElement(Label, null, "Slideshow delay:"), /*#__PURE__*/_react.default.createElement(_fields.TextInput, { type: "number", step: "0.5", min: "1", value: delay, onChange: e => setDelay(e.target.value) })), enableAlignment && /*#__PURE__*/_react.default.createElement(_alignSelector.AlignSelector, { align: align, options: [{ value: undefined, label: 'default' }, { value: 'left', label: 'left' }, { value: 'right', label: 'right' }], onChange: setAlign, onOpen: () => { var _contentWrapperRef$cu; const wrapper = (_contentWrapperRef$cu = contentWrapperRef.current) === null || _contentWrapperRef$cu === void 0 ? void 0 : _contentWrapperRef$cu.parentElement; if (wrapper) wrapper.scrollTop = wrapper.scrollHeight; } }))))), showImageUploader && /*#__PURE__*/_react.default.createElement(_imageUploader.ImageUploader, { onChange: onImageUploaderChange })); }