From 42b9910df04b997047bea9dfa469725c5851e5a8 Mon Sep 17 00:00:00 2001 From: 2betop <2betop.cn@gmail.com> Date: Tue, 7 Jan 2020 19:42:50 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9B=86=E6=88=90=E5=9B=BE=E7=89=87=E9=9B=86?= =?UTF-8?q?=E6=9F=A5=E7=9C=8B=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/components/CRUD/Fields.jsx | 11 +- examples/components/Form/Static.jsx | 44 +++++- scss/components/_image-gallery.scss | 204 ++++++++++++++++++++++++++++ scss/components/_modal.scss | 24 ++-- scss/components/_tooltip.scss | 2 +- scss/themes/cxd.scss | 1 + scss/themes/dark.scss | 1 + scss/themes/default.scss | 1 + src/components/ImageGallery.tsx | 177 ++++++++++++++++++++++++ src/components/Modal.tsx | 11 +- src/components/icons.tsx | 2 + src/factory.tsx | 43 +++--- src/renderers/Dialog.tsx | 1 + src/renderers/Image.tsx | 80 +++++------ src/renderers/Images.tsx | 67 ++++++++- src/renderers/Table.tsx | 46 ++++++- 16 files changed, 635 insertions(+), 80 deletions(-) create mode 100644 scss/components/_image-gallery.scss create mode 100644 src/components/ImageGallery.tsx diff --git a/examples/components/CRUD/Fields.jsx b/examples/components/CRUD/Fields.jsx index 89ca40a3..8ed7d612 100644 --- a/examples/components/CRUD/Fields.jsx +++ b/examples/components/CRUD/Fields.jsx @@ -30,10 +30,13 @@ export default { type: 'image', label: '图片', name: 'image', - popOver: { - title: '查看大图', - body: '
' - } + enlargeAble: true, + title: '233', + thumbMode: 'cover' + // popOver: { + // title: '查看大图', + // body: '' + // } }, { name: 'date', diff --git a/examples/components/Form/Static.jsx b/examples/components/Form/Static.jsx index ee0be700..4636c5a8 100644 --- a/examples/components/Form/Static.jsx +++ b/examples/components/Form/Static.jsx @@ -4,7 +4,39 @@ export default { data: { id: 1, image: - 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3893101144,2877209892&fm=23&gp=0.jpg' + 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3893101144,2877209892&fm=23&gp=0.jpg', + images: [ + { + image: + 'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692722/4f3cb4202335.jpeg@s_0,w_216,l_1,f_jpg,q_80', + src: + 'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692722/4f3cb4202335.jpeg' + }, + { + image: + 'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692942/d8e4992057f9.jpeg@s_0,w_216,l_1,f_jpg,q_80', + src: + 'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692942/d8e4992057f9.jpeg' + }, + { + image: + 'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395693148/1314a2a3d3f6.jpeg@s_0,w_216,l_1,f_jpg,q_80', + src: + 'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395693148/1314a2a3d3f6.jpeg' + }, + { + image: + 'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395693379/8f2e79f82be0.jpeg@s_0,w_216,l_1,f_jpg,q_80', + src: + 'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395693379/8f2e79f82be0.jpeg' + }, + { + image: + 'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395693566/552b175ef11d.jpeg@s_0,w_216,l_1,f_jpg,q_80', + src: + 'https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395693566/552b175ef11d.jpeg' + } + ] }, body: [ { @@ -112,6 +144,16 @@ export default { originalSrc: '${image}' }, + { + type: 'static-images', + label: '图片集', + name: 'images', + thumbMode: 'cover', + thumbRatio: '4:3', + enlargeAble: true, + originalSrc: '${src}' // 注意这个取变量是想对数组成员取的。 + }, + { type: 'divider' }, diff --git a/scss/components/_image-gallery.scss b/scss/components/_image-gallery.scss new file mode 100644 index 00000000..15f34aba --- /dev/null +++ b/scss/components/_image-gallery.scss @@ -0,0 +1,204 @@ +@keyframes disappear { + to { + opacity: 0; + } +} + +@keyframes appear { + from { + opacity: 0; + } +} + +.#{$ns}ImageGallery { + display: flex; + flex-direction: column; + background: transparent; + border: none; + border-radius: 0; + max-width: 1010px !important; + + &-close { + position: absolute; + right: 0; + top: 0; + color: rgba(255, 255, 255, 0.8); + cursor: pointer; + + &:hover { + color: #fff; + } + + > svg { + width: px2rem(16px); + height: px2rem(16px); + } + } + + &-title { + height: px2rem(30px); + vertical-align: top; + line-height: px2rem(30px); + font-size: px2rem(12px); + color: $white; + text-align: center; + } + + &-main { + background: #000; + flex-basis: 0; + flex-grow: 1; + position: relative; + display: flex; + justify-content: center; + align-items: center; + user-select: none; + + > img { + display: block; + max-width: 100%; + max-height: 100%; + } + } + + &-prevBtn, + &-nextBtn { + > svg { + width: px2rem(48px); + height: px2rem(48px); + } + + position: absolute; + top: 50%; + transform: translateY(-50%); + cursor: pointer; + color: #999; + text-shadow: rgba(0, 0, 0, 0.3) 0px 0px 4px; + + &:hover { + color: #fff; + text-shadow: rgba(0, 0, 0, 0.5) 0px 0px 4px; + } + animation-name: disappear; + animation-delay: 3s; + animation-duration: 0.35s; + animation-fill-mode: both; + + &.is-disabled { + pointer-events: none; + } + } + + &-main:hover &-prevBtn, + &-main:hover &-nextBtn { + animation-name: appear; + animation-delay: 0s; + animation-duration: 0.35s; + } + + &-prevBtn { + left: px2rem(20px); + } + + &-nextBtn { + right: px2rem(20px); + } + + &-footer { + height: px2rem(74px); + background: #222; + display: flex; + flex-direction: row; + user-select: none; + } + + &-prevList, + &-nextList { + width: px2rem(20px); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + + background: rgba(0, 0, 0, 0.3); + color: #fff; + + &.is-disabled { + background: rgba(0, 0, 0, 0.3); + color: rgba(255, 255, 255, 0.1); + pointer-events: none; + } + + &:hover { + background: rgba(0, 0, 0, 1); + color: #fff; + } + } + + &-itemsWrap { + flex-grow: 1; + flex-basis: 0; + width: 0; + overflow: hidden; + align-items: center; + justify-content: center; + display: flex; + } + + &-items { + display: inline-block; + white-space: nowrap; + } + + &-item { + margin: 10px 5px; + width: 54px; + height: 54px; + display: inline-flex; + position: relative; + border: 1px solid #666; + justify-content: center; + align-items: center; + cursor: pointer; + + > img { + display: block; + max-width: 100%; + max-height: 100%; + } + + @supports (object-fit: cover) { + > img { + width: 100%; + height: 100%; + object-fit: cover; + } + } + + &:after { + position: absolute; + content: ''; + display: block; + background: rgba(0, 0, 0, 0.5); + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + } + + &:hover { + border: 1px solid #e5e5e5; + &:after { + display: none; + } + } + + &.is-active { + border: 1px solid #108cee; + &:after { + display: none; + } + } + } +} diff --git a/scss/components/_modal.scss b/scss/components/_modal.scss index 8d99d8a2..dfa3f14a 100644 --- a/scss/components/_modal.scss +++ b/scss/components/_modal.scss @@ -219,14 +219,22 @@ color: $danger; } -.#{$ns}Modal--full .#{$ns}Modal-content { - width: calc(100% - 60px); - height: calc(100% - 60px); - max-width: unset; - margin: px2rem(30px); +.#{$ns}Modal--full { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; - > .#{$ns}Modal-body { - height: 0; - overflow: auto; + > .#{$ns}Modal-content { + flex-basis: 0; + flex-grow: 1; + margin: 30px; + width: calc(100% - 60px); + max-width: unset; + + > .#{$ns}Modal-body { + height: 0; + overflow: auto; + } } } diff --git a/scss/components/_tooltip.scss b/scss/components/_tooltip.scss index a92a4f90..e3c9d9ae 100644 --- a/scss/components/_tooltip.scss +++ b/scss/components/_tooltip.scss @@ -230,7 +230,7 @@ } &[data-position='left']:hover:after { - margin: 0 0 0 $Tooltip--attr-gap; + margin: 0 $Tooltip--attr-gap 0 0; } &[data-position='top']:after { diff --git a/scss/themes/cxd.scss b/scss/themes/cxd.scss index 844b2d36..ef007581 100644 --- a/scss/themes/cxd.scss +++ b/scss/themes/cxd.scss @@ -534,6 +534,7 @@ $Card-actions-onChecked-onHover-bg: $white; @import '../components/wrapper'; @import '../components/status'; @import '../components/carousel'; +@import '../components/image-gallery'; @import '../components/images'; @import '../components/form/fieldset'; diff --git a/scss/themes/dark.scss b/scss/themes/dark.scss index cb44c895..34447b70 100644 --- a/scss/themes/dark.scss +++ b/scss/themes/dark.scss @@ -200,6 +200,7 @@ pre { @import '../components/wrapper'; @import '../components/status'; @import '../components/carousel'; +@import '../components/image-gallery'; @import '../components/images'; @import '../components/form/fieldset'; diff --git a/scss/themes/default.scss b/scss/themes/default.scss index 8c8dcde9..1f887442 100644 --- a/scss/themes/default.scss +++ b/scss/themes/default.scss @@ -65,6 +65,7 @@ $Form-input-borderColor: #cfdadd; @import '../components/wrapper'; @import '../components/status'; @import '../components/carousel'; +@import '../components/image-gallery'; @import '../components/images'; @import '../components/form/fieldset'; diff --git a/src/components/ImageGallery.tsx b/src/components/ImageGallery.tsx new file mode 100644 index 00000000..fd36d23a --- /dev/null +++ b/src/components/ImageGallery.tsx @@ -0,0 +1,177 @@ +import React from 'react'; +import {themeable, ClassNamesFn} from '../theme'; +import {autobind} from '../utils/helper'; +import Modal from './Modal'; +import {Icon} from './icons'; + +export interface ImageGalleryProps { + classnames: ClassNamesFn; + classPrefix: string; + children: React.ReactNode; +} + +export interface ImageGalleryState { + isOpened: boolean; + index: number; + items: Array<{ + src: string; + originalSrc: string; + title?: string; + caption?: string; + }>; +} + +export class ImageGallery extends React.Component< + ImageGalleryProps, + ImageGalleryState +> { + state: ImageGalleryState = { + isOpened: false, + index: -1, + items: [] + }; + + @autobind + handleImageEnlarge(info: { + src: string; + originalSrc: string; + list?: Array<{ + src: string; + originalSrc: string; + title?: string; + caption?: string; + }>; + title?: string; + caption?: string; + index?: number; + }) { + this.setState({ + isOpened: true, + items: info.list ? info.list : [info], + index: info.index || 0 + }); + } + + @autobind + close() { + this.setState({ + isOpened: false + }); + } + + @autobind + prev() { + const index = this.state.index; + this.setState({ + index: index - 1 + }); + } + + @autobind + next() { + const index = this.state.index; + this.setState({ + index: index + 1 + }); + } + + @autobind + handleItemClick(e: React.MouseEvent