chore: support preview image in Modal

pull/1093/head
Benjy Cui 9 years ago
parent cf74561ef5
commit 5a08d410c5

@ -1,7 +1,8 @@
# 高级搜索
# Advanced Search
- category: 6
- order: 6
- chinese: 高级搜索
---

@ -1,7 +1,8 @@
# 表格:复杂数据
# Complex Table
- category: 5
- order: 5
- chinese: 表格:复杂数据
---

@ -1,7 +1,8 @@
# 表单
# Form
- category: 2
- order: 2
- chinese: 表单
---
@ -121,8 +122,8 @@
### 输入框宽度
<img class="preview-img" align="right" alt="正确示例" src="https://os.alipayobjects.com/rmsportal/vypllNQZsEHRszB.png" good>
<img class="preview-img" align="right" alt="错误示例" src="https://os.alipayobjects.com/rmsportal/XSLwnrlLbKFjiNj.png" bad>
<img class="preview-img good" align="right" alt="正确示例" src="https://os.alipayobjects.com/rmsportal/vypllNQZsEHRszB.png">
<img class="preview-img bad" align="right" alt="错误示例" src="https://os.alipayobjects.com/rmsportal/XSLwnrlLbKFjiNj.png">
当内容可预知,可以根据内容长短进行定义其落在多少个栅格上。

@ -1,8 +1,9 @@
# 典型页面
# Classic
- category: 0
- order: 0
- disabled: true
- chinese: 典型页面
---

@ -1,7 +1,8 @@
# 列表
# List
- category: 3
- order: 3
- chinese: 列表
---
@ -17,7 +18,7 @@
### 显示详情信息
<img class="preview-img" align="right" alt="气泡显示示例" description="使用『点击』触发时,应当保证激活/禁用的对称性,即在哪里打开,就在哪里关闭;另外。也支持用户点击空白区域关闭。<hr>使用『悬停』触发时,移入时设计约 0.5 秒的延时,然后激活详情气泡;移出时,立即关闭详情气泡。" src="https://os.alipayobjects.com/rmsportal/GmpRYixxnePBPPW.png">
<img class="preview-img" align="right" alt="气泡显示示例" description="使用『点击』触发时,应当保证激活/禁用的对称性,即在哪里打开,就在哪里关闭;另外。也支持用户点击空白区域关闭。使用『悬停』触发时,移入时设计约 0.5 秒的延时,然后激活详情气泡;移出时,立即关闭详情气泡。" src="https://os.alipayobjects.com/rmsportal/GmpRYixxnePBPPW.png">
气泡显示:用户鼠标点击/悬停某个链接或内容时,在悬浮层上显示该条列表项少量的详情信息。
@ -60,19 +61,19 @@
<br />
<img class="preview-img" align="right" alt="对等网格示例" noPadding src="https://os.alipayobjects.com/rmsportal/VDhwGyyblTSJpeV.png">
<img class="preview-img no-padding" align="right" alt="对等网格示例" src="https://os.alipayobjects.com/rmsportal/VDhwGyyblTSJpeV.png">
对等网格:以网格或者矩阵的方式排列内容元素,其中每个元素都有相仿的视觉重量。
### 显示图片
<img class="preview-img" align="right" alt="走马灯示例" noPadding src="https://os.alipayobjects.com/rmsportal/hKtAKuDfyfDpPrL.png">
<img class="preview-img no-padding" align="right" alt="走马灯示例" src="https://os.alipayobjects.com/rmsportal/hKtAKuDfyfDpPrL.png">
走马灯:以一维的形式来显示图片,可用户主动触发或者系统自动播放。
<br />
<img class="preview-img" align="right" alt="缩略图网格示例" noPadding src="https://os.alipayobjects.com/rmsportal/LAnBHEYiqWSfQAS.png">
<img class="preview-img no-padding" align="right" alt="缩略图网格示例" src="https://os.alipayobjects.com/rmsportal/LAnBHEYiqWSfQAS.png">
缩略图网格:以二维的形式来展现图片/Icon具有强烈的视觉效果可以吸引用户注意。

@ -1,7 +1,8 @@
# 导航
# Navigation
- category: 1
- order: 1
- chinese: 导航
---
@ -44,7 +45,7 @@
---
<img class="preview-img" noPadding align="right" alt="结构示例" src="https://os.alipayobjects.com/rmsportal/hutiGZWQYmIspjw.png">
<img class="preview-img no-padding" align="right" alt="结构示例" src="https://os.alipayobjects.com/rmsportal/hutiGZWQYmIspjw.png">
导航的结构由以下几部分组成。
@ -63,11 +64,11 @@
<br>
<img class="preview-img" noPadding align="right" alt="一级类目" src="https://os.alipayobjects.com/rmsportal/IeuIHdFfKCIABHV.png">
<img class="preview-img no-padding" align="right" alt="一级类目" src="https://os.alipayobjects.com/rmsportal/IeuIHdFfKCIABHV.png">
<img class="preview-img" noPadding align="right" alt="二级类目" src="https://os.alipayobjects.com/rmsportal/kAbbeJekohMtubV.png">
<img class="preview-img no-padding" align="right" alt="二级类目" src="https://os.alipayobjects.com/rmsportal/kAbbeJekohMtubV.png">
<img class="preview-img" noPadding align="right" alt="三级类目及以上" src="https://os.alipayobjects.com/rmsportal/qaOifucSTWooBTL.png">
<img class="preview-img no-padding" align="right" alt="三级类目及以上" src="https://os.alipayobjects.com/rmsportal/qaOifucSTWooBTL.png">
我们定义了不同类目层级所对应的导航样式。
@ -76,7 +77,7 @@
---
<img class="preview-img" noPadding align="right" alt="结构示例" src="https://os.alipayobjects.com/rmsportal/MVccMQxgCeYfwjS.png">
<img class="preview-img no-padding" align="right" alt="结构示例" src="https://os.alipayobjects.com/rmsportal/MVccMQxgCeYfwjS.png">
导航的结构由以下几部分组成。
@ -87,10 +88,10 @@
<br>
<img class="preview-img" noPadding align="right" alt="一级类目" src="https://os.alipayobjects.com/rmsportal/KvEsIDOYzknbsPT.png">
<img class="preview-img no-padding" align="right" alt="一级类目" src="https://os.alipayobjects.com/rmsportal/KvEsIDOYzknbsPT.png">
<img class="preview-img" noPadding align="right" alt="二级类目" src="https://os.alipayobjects.com/rmsportal/xXaCRVPIfmjDyIL.png">
<img class="preview-img no-padding" align="right" alt="二级类目" src="https://os.alipayobjects.com/rmsportal/xXaCRVPIfmjDyIL.png">
<img class="preview-img" noPadding align="right" alt="三级类目及以上" src="https://os.alipayobjects.com/rmsportal/ollkHeFUFQElelm.png">
<img class="preview-img no-padding" align="right" alt="三级类目及以上" src="https://os.alipayobjects.com/rmsportal/ollkHeFUFQElelm.png">
不同类目层级。

@ -1,7 +1,8 @@
# 表格
# Table
- category: 4
- order: 4
- chinese: 表格
---
@ -138,9 +139,9 @@
### 列宽
<img class="preview-img" align="right" alt="错误示例" src="https://os.alipayobjects.com/rmsportal/TbuuZNfOTrSflVg.png" bad>
<img class="preview-img bad" align="right" alt="错误示例" src="https://os.alipayobjects.com/rmsportal/TbuuZNfOTrSflVg.png" >
<img class="preview-img" align="right" alt="正确示例" src="https://os.alipayobjects.com/rmsportal/cSSSfNrFMioHDBJ.png" good>
<img class="preview-img good" align="right" alt="正确示例" src="https://os.alipayobjects.com/rmsportal/cSSSfNrFMioHDBJ.png">
一般是根据栅格来排版通过设定每一列的宽度比列来保证一定尺寸之上eg1366px有好的浏览效果。需要注意

@ -18,7 +18,7 @@ Ant Design 目前在外部也有 [许多产品实践](https://github.com/ant-des
### 金融云
<img as-cover class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/kBgLUfEwxlBdwUr.png">
<img class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/kBgLUfEwxlBdwUr.png">
<img class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/SeXqPPyixccDJBY.png">
<img class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/IRjHVNFWRlCMdnb.png">
@ -30,7 +30,7 @@ Ant Design 目前在外部也有 [许多产品实践](https://github.com/ant-des
### OceanBase Cloud Platform
<img as-cover class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/JUAXPZYtVyUQfGu.png">
<img class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/JUAXPZYtVyUQfGu.png">
<img class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/lpzTKvgLpJgKGpq.png">
<img class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/GVJGaWbqfBFedWN.png">
@ -42,7 +42,7 @@ OceanBase 是一款真正意义上的云端分布式关系型数据库,而 Oce
### 服务宝体验平台
<img as-cover class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/PiSveQClPzmxPTy.png">
<img class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/PiSveQClPzmxPTy.png">
<img class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/vsoYArBwcPRZnVE.png">
<img class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/TMyfsUGQSjOdGIm.png">
<img class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/sBlmIcJXZdJTJbC.png">
@ -56,7 +56,7 @@ OceanBase 是一款真正意义上的云端分布式关系型数据库,而 Oce
### AntV
<img as-cover class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/yWNVSFBhKsoShvi.png">
<img class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/yWNVSFBhKsoShvi.png">
<img class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/nvJftlNzfzhVDVW.png">
<img class="preview-img" width="420" align="right" src="https://os.alipayobjects.com/rmsportal/LugOCvzybKsmQCj.png">

@ -9,3 +9,4 @@ import './styles/clearfix.less';
import './styles/demo.less';
import './styles/page-nav.less';
import './styles/footer.less';
import './styles/preview-img.less';

@ -0,0 +1,87 @@
.preview-image-boxes {
float: right;
margin: 0 0 110px 60px;
width: 616px;
&-with-popup {
width: 420px;
}
}
.preview-image-boxes + .preview-image-boxes {
margin-top: -75px;
}
.preview-image-box {
width: 100%;
float: left;
padding: 0 8px;
}
.preview-image-wrapper {
background: #f4f4f4;
padding: 16px;
display: inline-block;
text-align: center;
width: 100%;
position: relative;
}
.preview-image-wrapper.good:after {
content: '';
width: 100%;
height: 3px;
background: #2db7f5;
display: block;
position: absolute;
bottom: 0;
left: 0;
}
.preview-image-wrapper.bad:after {
content: '';
width: 100%;
height: 3px;
background: #f50;
display: block;
position: absolute;
bottom: 0;
left: 0;
}
.preview-image-title {
font-size: 12px;
margin-top: 5px;
color: #666;
}
.preview-image-description {
font-size: 12px;
margin-top: 2px;
color: #999;
line-height: 1.5;
}
.preview-image-description hr {
margin: 2px 0;
border: 0;
background: none;
}
.preview-image-box img {
cursor: pointer;
max-width: 100%;
transition: all 0.3s ease;
background: #fff;
padding: 12px;
border-radius: 6px;
}
.preview-image-boxes.pack img {
padding: 0;
box-shadow: 0 1px 0 0 #ddd, 0 3px 0 0 #fff, 0 4px 0 0 #ddd, 0 6px 0 0 #fff, 0 7px 0 0 #ddd;
}
.preview-image-box img:hover {
box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.3);
}

@ -0,0 +1,101 @@
import React from 'react';
import { Modal, Carousel } from '../../../';
function isGood(className) {
return /\bgood\b/i.test(className);
}
function isBad(className) {
return /\bbad\b/i.test(className);
}
const parser = new DOMParser();
export default class ImagePreview extends React.Component {
constructor(props) {
super(props);
this.state = {
leftVisible: false,
rightVisible: false,
};
}
handleClick(side) {
this.setState({ [`${side}Visible`]: true });
}
handleCancel() {
this.setState({
leftVisible: false,
rightVisible: false,
});
}
render() {
const { className, imgs } = this.props;
const imgsMeta = imgs.map((img) => {
const xml = parser.parseFromString(img, 'application/xml');
const attributes = xml.firstChild.attributes;
const { alt, description, src } = attributes;
const imgClassName = attributes.class.nodeValue;
return {
alt: alt && alt.nodeValue,
description: description && description.nodeValue,
src: src.nodeValue,
isGood: isGood(imgClassName),
isBad: isBad(imgClassName),
};
});
const cover = imgsMeta[0];
const imagesList = imgsMeta.map((meta, index) => {
return <img {...meta} key={index} />;
});
const comparable = imgs.length === 2 &&
(imgsMeta[0].isGood || imgsMeta[0].isBad) &&
(imgsMeta[1].isGood || imgsMeta[1].isBad);
const style = comparable ? { width: '50%' } : null;
return (
<div className={className}>
<div className="preview-image-box"
style={style}
onClick={this.handleClick.bind(this, 'left')}>
<div className={`preview-image-wrapper ${cover.isGood && 'good'} ${cover.isBad && 'bad'}`}>
<img src={cover.src} alt="Sample Picture" />
</div>
<div className="preview-image-title">{cover.alt}</div>
<div className="preview-image-description">
{cover.description}
</div>
<Modal visible={this.state.leftVisible} title={null} footer={null}
onCancel={this.handleCancel.bind(this)}>
<Carousel>
{ comparable ? imagesList[0] : imagesList }
</Carousel>
</Modal>
</div>
{
comparable ?
<div className="preview-image-box"
style={style}
onClick={this.handleClick.bind(this, 'right')}>
<div className={`preview-image-wrapper ${imgsMeta[1].isGood && 'good'} ${imgsMeta[1].isBad && 'bad'}`}>
<img src={imgsMeta[1].src} alt="Sample Picture" />
</div>
<div className="preview-image-title">{imgsMeta[1].alt}</div>
<div className="preview-image-description">
{imgsMeta[1].description}
</div>
<Modal visible={this.state.rightVisible} title={null} footer={null}
onCancel={this.handleCancel.bind(this)}>
<Carousel>
{ comparable ? imagesList[1] : imagesList }
</Carousel>
</Modal>
</div> : null
}
</div>
);
}
}

@ -1,6 +1,27 @@
import React from 'react';
import classNames from 'classnames';
import ImagePreview from './ImagePreview';
import * as utils from '../utils';
function isPreviewImg(string) {
return /^<img\s/i.test(string) && /preview-img/gi.test(string);
}
function imgToPreview(node) {
if (!isPreviewImg(node.children)) {
return node;
}
const imgs = node.children.split(/\r|\n/);
const hasPopup = imgs.length > 1;
const previewClassName = classNames({
'preview-image-boxes': true,
clearfix: true,
'preview-image-boxes-with-popup': hasPopup,
});
return <ImagePreview className={previewClassName} imgs={imgs} />;
}
export default class Article extends React.Component {
render() {
const content = this.props.content;
@ -10,9 +31,11 @@ export default class Article extends React.Component {
return <li key={node.children}><a href={`#${node.children}`}>{ node.children }</a></li>;
});
content.description = content.description.map(imgToPreview);
return (
<article className="markdown">
<h1>{ content.meta.title }</h1>
<h1>{ content.meta.chinese }</h1>
{
jumper.length > 0 ?
<section className="toc"><ul>{ jumper }</ul></section> :

@ -3,11 +3,15 @@ import { Link } from 'react-router';
import { Row, Col, Menu } from '../../../';
import * as utils from '../utils';
function dashed(name) {
return name.toLowerCase().trim().replace(/\s+/g, '-');
}
export default class MainContent extends React.Component {
getMenuItems() {
const props = this.props;
return props.menuItems.map((item) => {
const key = item.english.toLowerCase();
const key = dashed(item.english);
const text = item.chinese || item.english;
const disabled = item.disabled === 'true';

@ -9,6 +9,10 @@ function isHeading(type) {
export function objectToComponent(object, index) {
if (object === null) return;
if (React.isValidElement(object)) {
return React.cloneElement(object, { key: index });
}
if (typeof object === 'string') {
return <span key={index}>{ object }</span>;
}

@ -2,12 +2,16 @@ import React from 'react';
import { Route, IndexRedirect } from 'react-router';
import Article from '../component/Article';
function dashed(name) {
return name.toLowerCase().trim().replace(/\s+/g, '-');
}
export function generateChildren(pagesData) {
const children = pagesData.map((pageData, index) => {
const ArticleWrapper = () => <Article content={pageData} />;
return (
<Route key={index}
path={pageData.meta.english.toLowerCase()}
path={dashed(pageData.meta.english)}
component={ArticleWrapper} />
);
});
@ -16,7 +20,7 @@ export function generateChildren(pagesData) {
});
children.unshift(
<IndexRedirect key="index"
to={firstChild.meta.english.toLowerCase()} />
to={dashed(firstChild.meta.english)} />
);
return children;
}

Loading…
Cancel
Save