diff --git a/docs/assets/thumbnail.png b/docs/assets/thumbnail.png new file mode 100644 index 0000000000..6c05a892d4 Binary files /dev/null and b/docs/assets/thumbnail.png differ diff --git a/docs/assets/thumbnaildiv.png b/docs/assets/thumbnaildiv.png new file mode 100644 index 0000000000..78b6096acb Binary files /dev/null and b/docs/assets/thumbnaildiv.png differ diff --git a/docs/client.js b/docs/client.js index 0bf1bb699e..ab68372e11 100644 --- a/docs/client.js +++ b/docs/client.js @@ -5,6 +5,8 @@ import './assets/style.css'; import './assets/carousel.png'; import './assets/logo.png'; import './assets/favicon.ico'; +import './assets/thumbnail.png'; +import './assets/thumbnaildiv.png'; import 'codemirror/mode/javascript/javascript'; import 'codemirror/theme/solarized.css'; diff --git a/docs/examples/.eslintrc b/docs/examples/.eslintrc index 86975f07e1..b6dc693611 100644 --- a/docs/examples/.eslintrc +++ b/docs/examples/.eslintrc @@ -48,6 +48,7 @@ "Table", "TabPane", "Tooltip", - "Well" + "Well", + "Thumbnail" } } diff --git a/docs/examples/ThumbnailAnchor.js b/docs/examples/ThumbnailAnchor.js new file mode 100644 index 0000000000..ccf1764101 --- /dev/null +++ b/docs/examples/ThumbnailAnchor.js @@ -0,0 +1,17 @@ +const thumbnailInstance = ( + + + + + + + + + + + + + +); + +React.render(thumbnailInstance, mountNode); diff --git a/docs/examples/ThumbnailDiv.js b/docs/examples/ThumbnailDiv.js new file mode 100644 index 0000000000..dc63bd0dfa --- /dev/null +++ b/docs/examples/ThumbnailDiv.js @@ -0,0 +1,38 @@ +const thumbnailInstance = ( + + + + +

Thumbnail label

+

Description

+

+   + +

+
+ + + +

Thumbnail label

+

Description

+

+   + +

+
+ + + +

Thumbnail label

+

Description

+

+   + +

+
+ +
+
+); + +React.render(thumbnailInstance, mountNode); diff --git a/docs/src/ComponentsPage.js b/docs/src/ComponentsPage.js index 82762d6386..8b7c815d37 100644 --- a/docs/src/ComponentsPage.js +++ b/docs/src/ComponentsPage.js @@ -449,6 +449,20 @@ const ComponentsPage = React.createClass({ + {/* Thumbnail */} +
+

Thumbnail

+

Thumbnails are designed to showcase linked images with minimal required markup. You can extend the grid component with thumbnails.

+ +

Anchor Thumbnail

+

Creates an anchor wrapping an image.

+ + +

Divider Thumbnail

+

Creates a divider wrapping an image and other children elements.

+ +
+ {/* ListGroup */}

List group ListGroup, ListGroupItem

@@ -606,15 +620,16 @@ const ComponentsPage = React.createClass({ Alerts Carousels Grids - List group - Labels - Badges - Jumbotron - Page Header - Wells - Glyphicons - Tables - Input + Thumbnail + List group + Labels + Badges + Jumbotron + Page Header + Wells + Glyphicons + Tables + Input Back to top diff --git a/docs/src/ReactPlayground.js b/docs/src/ReactPlayground.js index 7d2491aa9c..dc707b4d68 100644 --- a/docs/src/ReactPlayground.js +++ b/docs/src/ReactPlayground.js @@ -40,6 +40,7 @@ import * as modSplitButton from '../../src/SplitButton'; import * as modTabbedArea from '../../src/TabbedArea'; import * as modTable from '../../src/Table'; import * as modTabPane from '../../src/TabPane'; +import * as modThumbnail from '../../src/Thumbnail'; import * as modTooltip from '../../src/Tooltip'; import * as modWell from '../../src/Well'; @@ -88,6 +89,7 @@ const SplitButton = modSplitButton.default; const TabbedArea = modTabbedArea.default; const Table = modTable.default; const TabPane = modTabPane.default; +const Thumbnail = modThumbnail.default; const Tooltip = modTooltip.default; const Well = modWell.default; /* eslint-enable */ diff --git a/docs/src/Samples.js b/docs/src/Samples.js index 4ed0d89fd3..cd25d8d853 100644 --- a/docs/src/Samples.js +++ b/docs/src/Samples.js @@ -67,6 +67,8 @@ export default { CarouselUncontrolled: require('fs').readFileSync(__dirname + '/../examples/CarouselUncontrolled.js', 'utf8'), CarouselControlled: require('fs').readFileSync(__dirname + '/../examples/CarouselControlled.js', 'utf8'), GridBasic: require('fs').readFileSync(__dirname + '/../examples/GridBasic.js', 'utf8'), + ThumbnailAnchor: require('fs').readFileSync(__dirname + '/../examples/ThumbnailAnchor.js', 'utf8'), + ThumbnailDiv: require('fs').readFileSync(__dirname + '/../examples/ThumbnailDiv.js', 'utf8'), ListGroupDefault: require('fs').readFileSync(__dirname + '/../examples/ListGroupDefault.js', 'utf8'), ListGroupLinked: require('fs').readFileSync(__dirname + '/../examples/ListGroupLinked.js', 'utf8'), ListGroupActive: require('fs').readFileSync(__dirname + '/../examples/ListGroupActive.js', 'utf8'), diff --git a/src/Thumbnail.js b/src/Thumbnail.js new file mode 100644 index 0000000000..ea05cf85d2 --- /dev/null +++ b/src/Thumbnail.js @@ -0,0 +1,46 @@ +import React from 'react'; +import classSet from 'classnames'; +import BootstrapMixin from './BootstrapMixin'; + +const Thumbnail = React.createClass({ + mixins: [BootstrapMixin], + + getDefaultProps() { + return { + bsClass: 'thumbnail' + }; + }, + + render() { + let classes = this.getBsClassSet(); + + if(this.props.href) { + return ( + + {this.props.alt} + + ); + } + else { + if(this.props.children) { + return ( +
+ {this.props.alt} +
+ {this.props.children} +
+
+ ); + } + else { + return ( +
+ {this.props.alt} +
+ ); + } + } + } +}); + +export default Thumbnail; diff --git a/src/index.js b/src/index.js index 1f2bd5590b..118bacd7d9 100644 --- a/src/index.js +++ b/src/index.js @@ -48,6 +48,7 @@ import SubNav from './SubNav'; import TabbedArea from './TabbedArea'; import Table from './Table'; import TabPane from './TabPane'; +import Thumbnail from './Thumbnail'; import Tooltip from './Tooltip'; import Well from './Well'; import styleMaps from './styleMaps'; @@ -103,6 +104,7 @@ export default { TabbedArea, Table, TabPane, + Thumbnail, Tooltip, Well, styleMaps diff --git a/src/styleMaps.js b/src/styleMaps.js index 67992ae22d..54694e58ed 100644 --- a/src/styleMaps.js +++ b/src/styleMaps.js @@ -9,6 +9,7 @@ const styleMaps = { 'form': 'form', 'glyphicon': 'glyphicon', 'label': 'label', + 'thumbnail': 'thumbnail', 'list-group-item': 'list-group-item', 'panel': 'panel', 'panel-group': 'panel-group', diff --git a/test/ThumbnailSpec.js b/test/ThumbnailSpec.js new file mode 100644 index 0000000000..ba805cf2ea --- /dev/null +++ b/test/ThumbnailSpec.js @@ -0,0 +1,47 @@ +import React from 'react'; +import ReactTestUtils from 'react/lib/ReactTestUtils'; +import Thumbnail from '../src/Thumbnail'; + +describe('Thumbnail', function () { + it('Should have a thumbnail class and be an anchor', function () { + let instance = ReactTestUtils.renderIntoDocument( + + ); + assert.ok(instance.getDOMNode().className.match(/\bthumbnail\b/)); + assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'a')); + }); + + it('Should have an image', function () { + let instance = ReactTestUtils.renderIntoDocument( + + ); + assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'img')); + }); + + it('Should have a thumbnail class and be a div', function () { + let instance = ReactTestUtils.renderIntoDocument( + + ); + assert.ok(instance.getDOMNode().className.match(/\bthumbnail\b/)); + assert.equal(instance.getDOMNode().nodeName, 'DIV'); + }); + + it('Should have an image', function () { + let instance = ReactTestUtils.renderIntoDocument( + + ); + assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'img')); + }); + + it('Should have an inner div with class caption', function () { + let instance = ReactTestUtils.renderIntoDocument( + + Test +
+ Test child element +
+
+ ); + assert.ok(instance.getDOMNode().lastChild.className.match(/\bcaption\b/)); + }); +});