GridEditModal.jsx 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import {
  4. Modal, ModalHeader, ModalBody, ModalFooter,
  5. } from 'reactstrap';
  6. import { withTranslation } from 'react-i18next';
  7. import geu from './GridEditorUtil';
  8. import BootstrapGrid from '~/client/models/BootstrapGrid';
  9. const resSizes = BootstrapGrid.ResponsiveSize;
  10. const resSizeObj = {
  11. [resSizes.XS_SIZE]: { displayText: 'grid_edit.smart_no' },
  12. [resSizes.SM_SIZE]: { displayText: 'tablet' },
  13. [resSizes.MD_SIZE]: { displayText: 'desktop' },
  14. };
  15. class GridEditModal extends React.Component {
  16. constructor(props) {
  17. super(props);
  18. this.state = {
  19. colsRatios: [6, 6],
  20. responsiveSize: BootstrapGrid.ResponsiveSize.XS_SIZE,
  21. show: false,
  22. // use when re-edit grid
  23. // gridHtml: '',
  24. };
  25. this.checkResposiveSize = this.checkResposiveSize.bind(this);
  26. this.checkColsRatios = this.checkColsRatios.bind(this);
  27. // use when re-edit grid
  28. // this.init = this.init.bind(this);
  29. this.show = this.show.bind(this);
  30. this.hide = this.hide.bind(this);
  31. this.cancel = this.cancel.bind(this);
  32. this.pasteCodedGrid = this.pasteCodedGrid.bind(this);
  33. this.renderSelectedGridPattern = this.renderSelectedGridPattern.bind(this);
  34. this.renderBreakPointSetting = this.renderBreakPointSetting.bind(this);
  35. }
  36. async checkResposiveSize(rs) {
  37. await this.setState({ responsiveSize: rs });
  38. }
  39. async checkColsRatios(cr) {
  40. await this.setState({ colsRatios: cr });
  41. }
  42. // use when re-edit grid
  43. // init(gridHtml) {
  44. // const initGridHtml = gridHtml;
  45. // this.setState({ gridHtml: initGridHtml });
  46. // }
  47. show(gridHtml) {
  48. // use when re-edit grid
  49. // this.init(gridHtml);
  50. this.setState({ show: true });
  51. }
  52. hide() {
  53. this.setState({ show: false });
  54. }
  55. cancel() {
  56. this.hide();
  57. }
  58. pasteCodedGrid() {
  59. const { colsRatios, responsiveSize } = this.state;
  60. const convertedHTML = geu.convertRatiosAndSizeToHTML(colsRatios, responsiveSize);
  61. const spaceTab = ' ';
  62. const pastedGridData = `::: editable-row\n<div class="container">\n${spaceTab}<div class="row">\n${convertedHTML}\n${spaceTab}</div>\n</div>\n:::`;
  63. if (this.props.onSave != null) {
  64. this.props.onSave(pastedGridData);
  65. }
  66. this.cancel();
  67. }
  68. renderSelectedGridPattern() {
  69. const colsRatios = this.state.colsRatios;
  70. return colsRatios.join(' - ');
  71. }
  72. renderBreakPointSetting() {
  73. const { t } = this.props;
  74. const output = Object.entries(resSizeObj).map((responsiveSizeForMap) => {
  75. return (
  76. <div key={responsiveSizeForMap[0]} className="custom-control custom-radio custom-control-inline">
  77. <input
  78. type="radio"
  79. className="custom-control-input"
  80. id={responsiveSizeForMap[1].displayText}
  81. value={responsiveSizeForMap[1].displayText}
  82. checked={this.state.responsiveSize === responsiveSizeForMap[0]}
  83. onChange={e => this.checkResposiveSize(responsiveSizeForMap[0])}
  84. />
  85. <label className="custom-control-label" htmlFor={responsiveSizeForMap[1].displayText}>
  86. {t(responsiveSizeForMap[1].displayText)}
  87. </label>
  88. </div>
  89. );
  90. });
  91. return output;
  92. }
  93. renderGridDivisionMenu() {
  94. const gridDivisions = geu.mappingAllGridDivisionPatterns;
  95. const { t } = this.props;
  96. return (
  97. <div className="container">
  98. <div className="row">
  99. {gridDivisions.map((gridDivision) => {
  100. const numOfDivisions = gridDivision.numberOfGridDivisions;
  101. return (
  102. <div key={`${numOfDivisions}-divisions`} className="col-md-4 text-center">
  103. <h6 className="dropdown-header">{numOfDivisions} {t('grid_edit.division')}</h6>
  104. {gridDivision.mapping.map((gridOneDivision) => {
  105. const keyOfRow = `${numOfDivisions}-divisions-${gridOneDivision.join('-')}`;
  106. return (
  107. <button key={keyOfRow} className="dropdown-item" type="button" onClick={() => { this.checkColsRatios(gridOneDivision) }}>
  108. <div className="row">
  109. {gridOneDivision.map((god, i) => {
  110. const keyOfCol = `${keyOfRow}-${i}`;
  111. const className = `bg-info col-${god} border`;
  112. return <span key={keyOfCol} className={className}>{god}</span>;
  113. })}
  114. </div>
  115. </button>
  116. );
  117. })}
  118. </div>
  119. );
  120. })}
  121. </div>
  122. </div>
  123. );
  124. }
  125. renderPreview() {
  126. const { t } = this.props;
  127. const isMdSelected = this.state.responsiveSize === BootstrapGrid.ResponsiveSize.MD_SIZE;
  128. const isXsSelected = this.state.responsiveSize === BootstrapGrid.ResponsiveSize.XS_SIZE;
  129. return (
  130. <div className="row grw-grid-edit-preview border my-4 p-3">
  131. <div className="col-lg-2">
  132. <h4 className="d-block mt-2">{t('phone')}</h4>
  133. <div className="mobile-preview d-block px-3 py-2">
  134. {this.renderGridPreview(!isXsSelected)}
  135. </div>
  136. </div>
  137. <div className="col-lg-3">
  138. <h4 className="d-block mt-2">{t('tablet')}</h4>
  139. <div className="tablet-preview d-block px-3 py-2">
  140. {this.renderGridPreview(isMdSelected)}
  141. </div>
  142. </div>
  143. <div className="col-lg-4">
  144. <h4 className="d-block mt-2">{t('desktop')}</h4>
  145. <div className="desktop-preview d-block px-3 py-2">
  146. {this.renderGridPreview(false)}
  147. </div>
  148. </div>
  149. </div>
  150. );
  151. }
  152. renderGridPreview(isBreakEnabled) {
  153. const { colsRatios } = this.state;
  154. const convertedHTML = colsRatios.map((colsRatio, i) => {
  155. const ratio = isBreakEnabled ? 12 : colsRatio;
  156. const key = `grid-preview-col-${i}`;
  157. const className = `col-${ratio} grid-edit-border-for-each-cols`;
  158. return (
  159. <div key={key} className={`${key} ${className}`}></div>
  160. );
  161. });
  162. return (
  163. <div className="row">{convertedHTML}</div>
  164. );
  165. }
  166. render() {
  167. const { t } = this.props;
  168. return (
  169. <Modal isOpen={this.state.show} toggle={this.cancel} size="xl" className="grw-grid-edit-modal">
  170. <ModalHeader tag="h4" toggle={this.cancel} className="bg-primary text-light">
  171. {t('grid_edit.create_bootstrap_4_grid')}
  172. </ModalHeader>
  173. <ModalBody className="container">
  174. <div className="row">
  175. <div className="col-12">
  176. <h3 className="grw-modal-head">{t('grid_edit.grid_settings')}</h3>
  177. <form className="form-group mb-0">
  178. <div className="form-group row my-3">
  179. <label className="col-sm-3" htmlFor="gridPattern">
  180. {t('grid_edit.grid_pattern')}
  181. </label>
  182. <div className="col-sm-9">
  183. <button
  184. className="btn btn-outline-secondary dropdown-toggle"
  185. type="button"
  186. id="dropdownMenuButton"
  187. data-toggle="dropdown"
  188. aria-haspopup="true"
  189. aria-expanded="false"
  190. >
  191. {this.renderSelectedGridPattern()}
  192. </button>
  193. <div className="dropdown-menu grid-division-menu" aria-labelledby="dropdownMenuButton">
  194. {this.renderGridDivisionMenu()}
  195. </div>
  196. </div>
  197. </div>
  198. <div className="form-group row">
  199. <label className="col-sm-3" htmlFor="breakPoint">
  200. {t('grid_edit.break_point')}
  201. </label>
  202. <div className="col-sm-9">
  203. {this.renderBreakPointSetting()}
  204. </div>
  205. </div>
  206. </form>
  207. </div>
  208. </div>
  209. <h3 className="grw-modal-head">{t('preview')}</h3>
  210. <div className="col-12">
  211. {this.renderPreview()}
  212. </div>
  213. </ModalBody>
  214. <ModalFooter className="grw-modal-footer">
  215. <div className="ml-auto">
  216. <button type="button" className="mr-2 btn btn-secondary" onClick={this.cancel}>
  217. Cancel
  218. </button>
  219. <button type="button" className="btn btn-primary" onClick={this.pasteCodedGrid}>
  220. Done
  221. </button>
  222. </div>
  223. </ModalFooter>
  224. </Modal>
  225. );
  226. }
  227. }
  228. GridEditModal.propTypes = {
  229. onSave: PropTypes.func,
  230. t: PropTypes.func.isRequired,
  231. };
  232. export default withTranslation('translation', { withRef: true })(GridEditModal);