├── .nvmrc
├── .storybook
├── styles.css
├── preview-head.html
├── main.js
├── manager.js
├── webpack.config.js
└── preview.js
├── stories
├── reactivemaps
│ ├── placeholder.png
│ ├── Img.js
│ ├── ReactiveGoogleMap.stories.js
│ ├── ReactiveOpenStreetMapDefault.stories.js
│ ├── GeoDistanceDropDownOpenStreetMap.stories.js
│ ├── GeoDistanceDropdownGoogleMap.stories.js
│ ├── GeoDistanceSliderGoogleMap.stories.js
│ └── GeoDistanceSliderOpenStreetMap.stories.js
├── reactivesearch
│ ├── ReactiveElement
│ │ ├── index.js
│ │ ├── helper.js
│ │ ├── Basic.js
│ │ ├── WithStream.js
│ │ └── WithTheme.js
│ ├── CustomRecentIcon.js
│ ├── CustomPopularIcon.js
│ ├── Img.js
│ ├── SingleList.stories.js
│ ├── MultiDropdownList.stories.js
│ ├── SingleDropdownList.stories.js
│ ├── ResponsiveStory.js
│ ├── MultiList.stories.js
│ ├── ReactiveList.stories.js
│ ├── NumberBox.stories.js
│ ├── DynamicRangeSlider.stories.js
│ ├── ErrorBoundary.stories.js
│ ├── Dark.stories.js
│ ├── RangeSlider.stories.js
│ ├── RangeInput.stories.js
│ ├── TagCloud.stories.js
│ ├── ResultCard.stories.js
│ ├── MultiRange.stories.js
│ ├── SingleRange.stories.js
│ ├── ResultList.stories.js
│ ├── MultiDropdownRange.stories.js
│ ├── SearchBox.stories.js
│ ├── SingleDropdownRange.stories.js
│ ├── MultiDataList.stories.js
│ ├── SingleDataList.stories.js
│ ├── ToggleButton.stories.js
│ ├── RatingsFilter.stories.js
│ ├── SearchBoxControlledUsage.stories.js
│ ├── AIAnswer.stories.js
│ ├── TreeList.stories.js
│ ├── MultiListWithIndexProp.js
│ ├── SearchBoxWithIndexProp.js
│ ├── ReactiveComponentWithDistinctFieldProp.js
│ ├── DarkCard.stories.js
│ ├── ReactiveComponent.stories.js
│ ├── TagCloudDark.stories.js
│ ├── TabDataList.stories.js
│ ├── DatePickerDark.stories.js
│ ├── DatePicker.stories.js
│ ├── DateRange.stories.js
│ ├── DateRangeDark.stories.js
│ ├── list.css
│ ├── resultViews
│ │ └── index.js
│ ├── TreeListCustomRenderer.stories.js
│ ├── TreeListCustomSelectedFilters.stories.js
│ ├── KNNSearch.stories.js
│ └── SearchBoxWithCustomAIRender.stories.js
├── utils
│ └── renderItem.js
└── styles.css
├── .gitignore
├── README.md
├── package.json
├── examples
└── KNNSearch
│ └── index.js
└── LICENSE
/.nvmrc:
--------------------------------------------------------------------------------
1 | v18
2 |
--------------------------------------------------------------------------------
/.storybook/styles.css:
--------------------------------------------------------------------------------
1 | .hljs {
2 | display: inline;
3 | }
4 |
--------------------------------------------------------------------------------
/stories/reactivemaps/placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appbaseio/playground/HEAD/stories/reactivemaps/placeholder.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log.*
3 | .DS_Store
4 | storybook-static/
5 | .yarn-error.log
6 | npm-debug.log*
7 | yarn-error.log
8 |
--------------------------------------------------------------------------------
/.storybook/preview-head.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/stories/reactivesearch/ReactiveElement/index.js:
--------------------------------------------------------------------------------
1 | import Basic from "./Basic";
2 | import WithStream from "./WithStream";
3 | import WithTheme from "./WithTheme";
4 |
5 | module.exports = {
6 | Basic,
7 | WithStream,
8 | WithTheme
9 | };
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # playground
2 |
3 | A storybook playground for ReactiveMaps and ReactiveSearch projects.
4 |
5 | # Running Locally
6 |
7 | ```
8 | npm run storybook
9 | ```
10 |
11 | # Deploying
12 |
13 | ```
14 | npm run deploy-storybook
15 | ```
16 |
--------------------------------------------------------------------------------
/.storybook/main.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | stories: ["../stories/index.js"],
3 | addons: [
4 | "@storybook/addon-knobs",
5 | "storybook-readme",
6 | "@storybook/addon-actions",
7 | "@storybook/addon-a11y",
8 | ],
9 | reactOptions: { legacyRootApi: false },
10 | };
11 |
--------------------------------------------------------------------------------
/.storybook/manager.js:
--------------------------------------------------------------------------------
1 | import "./styles.css";
2 | import { addons } from "@storybook/addons";
3 | import { create } from "@storybook/theming/create";
4 |
5 | const theme = create({
6 | base: "light",
7 | brandTitle: "ReactiveSearch",
8 | brandUrl: "https://github.com/appbaseio/playground",
9 | });
10 |
11 | addons.setConfig({
12 | panelPosition: "bottom",
13 | theme,
14 | });
15 |
--------------------------------------------------------------------------------
/stories/reactivesearch/CustomRecentIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const CustomRecentIcon = () => (
4 |
11 |
12 |
13 | );
14 |
15 | export default CustomRecentIcon;
16 |
--------------------------------------------------------------------------------
/.storybook/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | module: {
3 | rules: [
4 | {
5 | test: /\.css$/,
6 | use: ["style-loader", "css-loader"]
7 | },
8 | {
9 | test: /\.(ttf|eot|png|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
10 | use : "file-loader"
11 | },
12 | {
13 | test: /\.m?js$/,
14 | exclude: /(node_modules|bower_components)/,
15 | use: {
16 | loader: 'babel-loader',
17 | options: {
18 | presets: ["@babel/preset-env", "@babel/preset-react"],
19 | }
20 | }
21 | }
22 | ]
23 | },
24 | externals: ["ws"]
25 | }
26 |
--------------------------------------------------------------------------------
/stories/reactivesearch/ReactiveElement/helper.js:
--------------------------------------------------------------------------------
1 | import _ from "lodash";
2 |
3 | export var GetTopTopics = function (data) {
4 | const store = {};
5 | let topics = [];
6 | data.forEach((singleData) => {
7 | singleData._source.group.group_topics.forEach((topic) => {
8 | store[topic.topic_name] = store[topic.topic_name] ? store[topic.topic_name] + 1 : 1;
9 | });
10 | });
11 | for (const topic in store) {
12 | const obj = {
13 | name: topic,
14 | value: store[topic]
15 | };
16 | topics.push(obj);
17 | }
18 | topics = _.sortBy(topics, "value").reverse();
19 | return topics;
20 | };
21 |
--------------------------------------------------------------------------------
/stories/reactivesearch/CustomPopularIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const CustomPopularIcon = () => (
4 |
11 |
12 |
13 | );
14 |
15 | export default CustomPopularIcon;
16 |
--------------------------------------------------------------------------------
/stories/reactivemaps/Img.js:
--------------------------------------------------------------------------------
1 | import { default as React, Component } from "react";
2 |
3 | export class Img extends Component {
4 | constructor(props) {
5 | super(props);
6 | this.state = {
7 | src: this.props.src
8 | };
9 | this.stopImg = false;
10 | }
11 |
12 | componentDidMount() {
13 | const self = this;
14 | const defaultSrc = "https://s-media-cache-ak0.pinimg.com/216x146/27/b2/da/27b2da4789262e3b828a8ec6587dd8aa.jpg";
15 |
16 | this.img = new Image();
17 |
18 | this.img.onerror = function() {
19 | self.setState({
20 | src: defaultSrc
21 | });
22 | };
23 |
24 | this.img.src = this.state.src;
25 | }
26 |
27 | componentWillUnmount() {
28 | this.stopImg = true;
29 | }
30 |
31 | render() {
32 | return ;
33 | }
34 | };
35 |
--------------------------------------------------------------------------------
/stories/reactivesearch/Img.js:
--------------------------------------------------------------------------------
1 | import { default as React, Component } from "react";
2 |
3 | export class Img extends Component {
4 | constructor(props) {
5 | super(props);
6 | this.state = {
7 | src: this.props.src
8 | };
9 | this.stopImg = false;
10 | }
11 |
12 | componentDidMount() {
13 | const self = this;
14 | this.img = new Image();
15 | const defaultSrc = "https://s-media-cache-ak0.pinimg.com/216x146/27/b2/da/27b2da4789262e3b828a8ec6587dd8aa.jpg";
16 | this.img.onerror = function () {
17 | self.setState({
18 | src: defaultSrc
19 | }, () => {
20 |
21 | });
22 | };
23 | this.img.src = this.state.src;
24 | }
25 |
26 | componentWillUnmount() {
27 | this.stopImg = true;
28 | }
29 |
30 | render() {
31 | return ;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/stories/utils/renderItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export const renderBookItemWithDate = (suggestion) => {
4 | if (suggestion._suggestion_type === 'document') {
5 | return (
6 |
7 | {suggestion._source.original_title}
8 |
16 | {new Date(Number(suggestion._source._timestamp) * 1000).toDateString() || ''}
17 |
18 |
19 | );
20 | }
21 | return null;
22 | };
23 |
24 | export const renderBookItemWithLink = (suggestion) => {
25 | return (
26 |
38 | {suggestion._source.original_title}
39 |
40 | );
41 | };
42 |
--------------------------------------------------------------------------------
/stories/reactivesearch/SingleList.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, SelectedFilters, SingleList, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksReactiveList } from "./resultViews";
5 |
6 | export default class SingleListDefault extends Component {
7 | render() {
8 | return (
9 |
14 |
15 |
16 |
22 |
23 |
24 |
25 |
26 |
37 |
38 |
39 |
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/stories/reactivesearch/MultiDropdownList.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, SelectedFilters, MultiDropdownList, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksReactiveList } from "./resultViews";
5 |
6 | export default class MultiDropdownListDefault extends Component {
7 | render() {
8 | return (
9 |
14 |
15 |
16 |
22 |
23 |
24 |
25 |
26 |
37 |
38 |
39 |
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/stories/reactivesearch/SingleDropdownList.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, SelectedFilters, SingleDropdownList, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksReactiveList } from "./resultViews";
5 |
6 | export default class SingleDropdownListDefault extends Component {
7 | render() {
8 | return (
9 |
14 |
15 |
16 |
22 |
23 |
24 |
25 |
26 |
37 |
38 |
39 |
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/.storybook/preview.js:
--------------------------------------------------------------------------------
1 | import { addDecorator } from "@storybook/react";
2 | import { withKnobs } from "@storybook/addon-knobs";
3 |
4 | import { addReadme } from "storybook-readme";
5 |
6 | addDecorator(withKnobs);
7 | addDecorator(addReadme);
8 | export const parameters = {
9 | a11y: {
10 | element: "#storybook-root",
11 | config: {},
12 | options: {},
13 | manual: true,
14 | },
15 | };
16 |
17 |
18 | /**
19 | * Workaround for knobs not updating. Look at github issue for more details.
20 | * https://github.com/storybookjs/addon-knobs/issues/19
21 | *
22 | */
23 | let currentPath;
24 | let timeout = 500;
25 |
26 | if (window.parent) {
27 | const parentWindow = window.parent;
28 | parentWindow.setInterval(function () {
29 | const urlParams = new URLSearchParams(parentWindow.location.search);
30 | const path = urlParams.get('path');
31 |
32 | if (path && path !== currentPath) {
33 | currentPath = path;
34 |
35 | const knobButtons = parentWindow.document.querySelectorAll(
36 | '#panel-tab-content button',
37 | );
38 |
39 | if (knobButtons.length) {
40 | const resetButton = knobButtons[knobButtons.length - 1];
41 | resetButton.click();
42 | }else{
43 | currentPath = ""
44 | }
45 | }
46 | }, timeout);
47 | }
48 |
--------------------------------------------------------------------------------
/stories/reactivesearch/ResponsiveStory.js:
--------------------------------------------------------------------------------
1 | var $ = require("jquery");
2 |
3 | var ResponsiveStory = function ResponsiveStory() {
4 | var paginationHeight = function paginationHeight() {
5 | return $(".rbc-pagination").length * 85;
6 | };
7 |
8 | var getHeight = function getHeight(item) {
9 | return item.height() ? item.height() : 0;
10 | };
11 |
12 | var handleResponsive = function handleResponsive() {
13 | var height = $(window).height();
14 | var resultHeight = height - 15;
15 | $(".rbc.rbc-reactivelist, .rbc.rbc-reactiveelement").css({
16 | maxHeight: resultHeight
17 | });
18 | var $component = [$(".rbc.rbc-singlelist"), $(".rbc.rbc-multilist"), $(".rbc.rbc-nestedlist"), $(".rbc.rbc-tagcloud")];
19 | $component.forEach(function (item) {
20 | if (item.length) {
21 | var itemHeader = getHeight(item.find(".rbc-title")) + getHeight(item.find(".rbc-search-container"));
22 | item.find(".rbc-list-container").css({ maxHeight: height - itemHeader - 35 });
23 | }
24 | });
25 | $(".rbc-base > .row").css({
26 | "margin-bottom": 0
27 | });
28 | $(".rbc-reactivemap .rbc-container").css({
29 | maxHeight: height
30 | });
31 | };
32 |
33 | handleResponsive();
34 |
35 | $(window).resize(function () {
36 | handleResponsive();
37 | });
38 | };
39 |
40 | export default ResponsiveStory;
--------------------------------------------------------------------------------
/stories/reactivesearch/MultiList.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, SelectedFilters, MultiList, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksReactiveList } from "./resultViews";
5 |
6 | export default class MultiListDefault extends Component {
7 | render() {
8 | return (
9 |
14 |
15 |
16 |
25 |
26 |
27 |
28 |
29 |
40 |
41 |
42 |
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/stories/reactivesearch/ReactiveList.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, MultiDropdownList, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksReactiveList } from "./resultViews";
5 |
6 | export default class ReactiveListDefault extends Component {
7 | render() {
8 | const {scrollTargetStory, ...otherProps} = this.props;
9 | const scrollStyle = scrollTargetStory ? ({
10 | overflow : 'scroll',
11 | height: '80vh'
12 | }) : {};
13 | return (
14 |
19 |
20 |
21 |
27 |
28 |
29 |
30 |
42 |
43 |
44 |
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/stories/reactivesearch/NumberBox.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, NumberBox, ReactiveList, SelectedFilters } from "@appbaseio/reactivesearch";
3 |
4 | import { booksList as BooksList } from "./resultViews";
5 |
6 | export default class NumberBoxDefault extends Component {
7 | render() {
8 | return (
9 |
14 |
15 |
16 |
21 |
22 |
23 |
24 |
35 | {({ data }) => (
36 |
37 | {
38 | data.map(item => )
39 | }
40 |
41 | )}
42 |
43 |
44 |
45 |
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/stories/reactivesearch/DynamicRangeSlider.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import {
3 | ReactiveBase,
4 | DynamicRangeSlider,
5 | SelectedFilters,
6 | ReactiveList
7 | } from "@appbaseio/reactivesearch";
8 |
9 | import { booksList as BooksList } from "./resultViews";
10 |
11 | export default class DynamicRangeSliderDefault extends Component {
12 | render() {
13 | return (
14 |
19 |
20 |
21 |
26 |
27 |
28 |
29 |
30 |
41 | {({ data }) => (
42 |
43 | {
44 | data.map(item => )
45 | }
46 |
47 | )}
48 |
49 |
50 |
51 |
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/stories/reactivesearch/ErrorBoundary.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import {
3 | ReactiveBase,
4 | DynamicRangeSlider,
5 | SelectedFilters,
6 | ReactiveList,
7 | ErrorBoundary
8 | } from "@appbaseio/reactivesearch";
9 |
10 | import { booksList as BooksList } from "./resultViews";
11 |
12 | export default class ErrorBoundaryDefault extends Component {
13 | render() {
14 | return (
15 |
20 |
21 |
22 |
23 |
27 |
28 |
29 |
30 |
31 |
32 |
43 | {({ data }) => (
44 |
45 | {
46 | data.map(item => )
47 | }
48 |
49 | )}
50 |
51 |
52 |
53 |
54 | );
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/stories/reactivesearch/Dark.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, ReactiveList, SelectedFilters, SearchBox } from "@appbaseio/reactivesearch";
3 |
4 | import { booksList as BooksList } from "./resultViews";
5 |
6 | export default class DarkStoriesComponent extends Component {
7 | render() {
8 | return (
9 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
27 |
28 |
40 | {({ data }) => (
41 |
42 | {
43 | data.map(item => )
44 | }
45 |
46 | )}
47 |
48 |
49 |
50 |
51 | );
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/stories/reactivesearch/RangeSlider.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import {
3 | ReactiveBase,
4 | RangeSlider,
5 | SelectedFilters,
6 | ReactiveList
7 | } from "@appbaseio/reactivesearch";
8 |
9 | import { booksList as BooksList } from "./resultViews";
10 |
11 | export default class RangeSliderDefault extends Component {
12 | render() {
13 | return (
14 |
19 |
20 |
21 |
34 |
35 |
36 |
37 |
38 |
49 | {({ data }) => (
50 |
51 | {
52 | data.map(item => )
53 | }
54 |
55 | )}
56 |
57 |
58 |
59 |
60 | );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/stories/reactivesearch/RangeInput.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import {
3 | ReactiveBase,
4 | RangeInput,
5 | SelectedFilters,
6 | ReactiveList
7 | } from "@appbaseio/reactivesearch";
8 |
9 | import { booksList as BooksList } from "./resultViews";
10 |
11 | export default class RangeInputDefault extends Component {
12 | render() {
13 | return (
14 |
19 |
20 |
21 |
34 |
35 |
36 |
37 |
38 |
50 | {({ data }) => (
51 |
52 | {
53 | data.map(item => )
54 | }
55 |
56 | )}
57 |
58 |
59 |
60 |
61 | );
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/stories/reactivesearch/TagCloud.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, TagCloud, SelectedFilters, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { meetupList as MeetupList } from "./resultViews";
5 |
6 | export default class TagCloudDefault extends Component {
7 | render() {
8 | return (
9 |
14 |
15 |
16 |
22 |
23 |
24 |
25 |
42 | {({ data }) => (
43 |
44 | {
45 | data.map(item => )
46 | }
47 |
48 | )}
49 |
50 |
51 |
52 |
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/stories/reactivesearch/ResultCard.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, SingleDropdownRange, ResultCard, ReactiveList } from "@appbaseio/reactivesearch";
3 | import { booksCard as BooksCard } from "./resultViews";
4 |
5 | export default class ResultCardDefault extends Component {
6 | render() {
7 | return (
8 |
13 |
14 |
15 | 4" }]
23 | }
24 | />
25 |
26 |
27 |
37 | {
38 | ({ data }) => (
39 |
40 | {
41 | data.map(item => )
42 | }
43 |
44 | )
45 | }
46 |
47 |
48 |
49 |
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/stories/reactivesearch/MultiRange.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, MultiRange, SelectedFilters, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksCard as BooksCard } from "./resultViews";
5 |
6 | export default class MultiRangeDefault extends Component {
7 | render() {
8 | return (
9 |
14 |
15 |
16 | 4" }]
23 | }
24 | {...this.props}
25 | />
26 |
27 |
28 |
29 |
39 | {
40 | ({ data }) => (
41 |
42 | {
43 | data.map(item => )
44 | }
45 |
46 | )
47 | }
48 |
49 |
50 |
51 |
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/stories/reactivesearch/SingleRange.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, SingleRange, SelectedFilters, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksCard as BooksCard } from "./resultViews";
5 |
6 | export default class SingleRangeDefault extends Component {
7 | render() {
8 | return (
9 |
14 |
15 |
16 | 4" }]
23 | }
24 | {...this.props}
25 | />
26 |
27 |
28 |
29 |
39 | {
40 | ({ data }) => (
41 |
42 | {
43 | data.map(item => )
44 | }
45 |
46 | )
47 | }
48 |
49 |
50 |
51 |
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/stories/reactivesearch/ResultList.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, SingleDropdownRange, ResultList, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksList as BooksList } from "./resultViews";
5 |
6 | export default class ResultListDefault extends Component {
7 | render() {
8 | return (
9 |
14 |
15 |
16 | 4" }]
24 | }
25 | />
26 |
27 |
28 |
40 | {({ data }) => (
41 |
42 | {
43 | data.map(item => )
44 | }
45 |
46 | )}
47 |
48 |
49 |
50 |
51 | );
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/stories/reactivesearch/MultiDropdownRange.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, MultiDropdownRange, SelectedFilters, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksCard as BooksCard } from "./resultViews";
5 |
6 | export default class MultiDropdownRangeDefault extends Component {
7 | render() {
8 | return (
9 |
14 |
15 |
16 | 4" }]
23 | }
24 | {...this.props}
25 | />
26 |
27 |
28 |
29 |
39 | {
40 | ({ data }) => (
41 |
42 | {
43 | data.map(item => )
44 | }
45 |
46 | )
47 | }
48 |
49 |
50 |
51 |
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/stories/reactivesearch/SearchBox.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, SearchBox, SelectedFilters, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksList as BooksList } from "./resultViews";
5 |
6 | export default class SearchBoxDefault extends Component {
7 | render() {
8 | return (
9 |
19 |
20 |
21 |
27 |
28 |
29 |
30 |
41 | {({ data }) => (
42 |
43 | {
44 | data.map(item => )
45 | }
46 |
47 | )}
48 |
49 |
50 |
51 |
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/stories/reactivesearch/SingleDropdownRange.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, SingleDropdownRange, SelectedFilters, ReactiveList } from "@appbaseio/reactivesearch";
3 | import { booksCard as BooksCard } from "./resultViews";
4 |
5 | export default class SingleDropdownRangeDefault extends Component {
6 | render() {
7 | return (
8 |
13 |
14 |
15 | 4" }]
22 | }
23 | {...this.props}
24 | />
25 |
26 |
27 |
28 |
38 | {
39 | ({ data }) => (
40 |
41 | {
42 | data.map(item => )
43 | }
44 |
45 | )
46 | }
47 |
48 |
49 |
50 |
51 | );
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/stories/reactivesearch/MultiDataList.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, MultiDataList, ReactiveList, SelectedFilters } from "@appbaseio/reactivesearch";
3 |
4 | import { meetupList as MeetupList } from "./resultViews";
5 |
6 | export default class MultiDataListDefault extends Component {
7 | render() {
8 | return (
9 |
14 |
15 |
16 |
27 |
28 |
29 |
30 |
44 | {({ data }) => (
45 |
46 | {
47 | data.map(item => )
48 | }
49 |
50 | )}
51 |
52 |
53 |
54 |
55 | );
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/stories/reactivesearch/SingleDataList.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, SingleDataList, ReactiveList, SelectedFilters } from "@appbaseio/reactivesearch";
3 |
4 | import { meetupList as MeetupList } from "./resultViews";
5 |
6 | export default class SingleDataListDefault extends Component {
7 | render() {
8 | return (
9 |
14 |
15 |
16 |
27 |
28 |
29 |
30 |
44 | {({ data }) => (
45 |
46 | {
47 | data.map(item => )
48 | }
49 |
50 | )}
51 |
52 |
53 |
54 |
55 | );
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/stories/reactivesearch/ToggleButton.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, ToggleButton, ReactiveList, SelectedFilters } from "@appbaseio/reactivesearch";
3 |
4 | import { meetupList as MeetupList } from "./resultViews";
5 |
6 | export default class ToggleButtonDefault extends Component {
7 | render() {
8 | return (
9 |
14 |
15 |
16 |
26 |
27 |
28 |
29 |
46 | {({ data }) => (
47 |
48 | {
49 | data.map(item => )
50 | }
51 |
52 | )}
53 |
54 |
55 |
56 |
57 | );
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/stories/reactivesearch/RatingsFilter.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, RatingsFilter, ReactiveList, SelectedFilters, ResultCard } from "@appbaseio/reactivesearch";
3 | import ResponsiveStory from "./ResponsiveStory";
4 | import { booksCard as BooksCard } from './resultViews';
5 |
6 | export default class RatingsFilterDefault extends Component {
7 |
8 | componentDidMount() {
9 | ResponsiveStory();
10 | }
11 |
12 | render() {
13 | return (
14 |
19 |
20 |
21 |
22 | 1 stars' },
31 | ]}
32 | {...this.props}
33 | />
34 |
35 |
36 |
37 |
48 | {
49 | ({ data }) => (
50 |
51 | {
52 | data.map(item => (
53 |
54 | ))
55 | }
56 |
57 | )
58 | }
59 |
60 |
61 |
62 |
63 | );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/stories/reactivesearch/ReactiveElement/Basic.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, MultiList, ReactiveElement } from "@appbaseio/reactivesearch";
3 | import ResponsiveStory from "../ResponsiveStory";
4 | import { Img } from "../Img.js";
5 |
6 | require("../list.css");
7 |
8 | export default class Basic extends Component {
9 | constructor(props) {
10 | super(props);
11 | this.cityQuery = this.cityQuery.bind(this);
12 | this.DEFAULT_IMAGE = "http://www.avidog.com/wp-content/uploads/2015/01/BellaHead082712_11-50x65.jpg";
13 | }
14 |
15 | cityQuery(value) {
16 | if (value) {
17 | const field = "group.group_city.group_city_simple";
18 | const query = JSON.parse(`{"${field}":${JSON.stringify(value)}}`);
19 | return { terms: query };
20 | } return null;
21 | }
22 |
23 | componentDidMount() {
24 | ResponsiveStory();
25 | }
26 |
27 | render() {
28 | return (
29 |
34 |
35 |
36 |
47 |
48 |
49 |
50 |
61 |
62 |
63 |
64 | );
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "playground",
3 | "version": "1.0.0",
4 | "description": "Reactive storybook playground",
5 | "main": "index.js",
6 | "scripts": {
7 | "storybook": "start-storybook -p 9009",
8 | "build-storybook": "build-storybook",
9 | "deploy-storybook": "storybook-to-ghpages"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/appbaseio/playground.git"
14 | },
15 | "author": "metagrover",
16 | "license": "Apache-2.0",
17 | "bugs": {
18 | "url": "https://github.com/appbaseio/reactive-playground/issues"
19 | },
20 | "homepage": "https://github.com/appbaseio/reactive-playground#readme",
21 | "dependencies": {
22 | "@appbaseio/reactivemaps": "4.0.0",
23 | "@appbaseio/reactivesearch": "4.3.0",
24 | "docs": "appbaseio/Docs#dev",
25 | "moment": "^2.29.1",
26 | "react": "^18.2.0",
27 | "react-dom": "^18.2.0",
28 | "remarkable": "^2.0.1"
29 | },
30 | "devDependencies": {
31 | "@babel/core": "^7.19.6",
32 | "@babel/preset-env": "^7.19.4",
33 | "@babel/preset-react": "^7.18.6",
34 | "@storybook/addon-a11y": "^6.5.16",
35 | "@storybook/addon-actions": "^6.5.16",
36 | "@storybook/addon-info": "^6.0.0-alpha.2",
37 | "@storybook/addon-knobs": "^6.4.0",
38 | "@storybook/addon-options": "^6.0.0-alpha.29",
39 | "@storybook/react": "^6.5.16",
40 | "@storybook/storybook-deployer": "^2.8.16",
41 | "babel-loader": "^8.2.2",
42 | "css-loader": "^0.27.3",
43 | "file-loader": "^4.0.0",
44 | "jquery": "^3.4.1",
45 | "json-loader": "^0.5.4",
46 | "materialize-css": "^0.98.1",
47 | "raw-loader": "^0.5.1",
48 | "storybook-readme": "^5.0.9",
49 | "sumoselect": "^3.0.3"
50 | },
51 | "engines": {
52 | "node": ">=14.17.1"
53 | }
54 | }
--------------------------------------------------------------------------------
/stories/reactivesearch/SearchBoxControlledUsage.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component, useState } from "react";
2 | import { ReactiveBase, SearchBox, SelectedFilters, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksList as BooksList } from "./resultViews";
5 |
6 | export default function SearchBoxControlledUsage(props) {
7 | const [value, setValue] = useState("")
8 | const {enableRecentSuggestions} = props
9 | return (
10 |
19 |
20 |
21 | {
26 | v?setValue(v): setValue("")
27 | if(props.shouldTriggerQueryWhileTyping){
28 | triggerQuery()
29 | }
30 | }}
31 | searchboxId={props.enableFAQSuggestions?"rs_docs":undefined}
32 | {...props}
33 | />
34 |
35 |
36 |
37 |
48 | {({ data }) => (
49 |
50 | {
51 | data.map(item => )
52 | }
53 |
54 | )}
55 |
56 |
57 |
58 |
59 | );
60 | }
61 |
--------------------------------------------------------------------------------
/stories/reactivesearch/AIAnswer.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, SearchBox, SelectedFilters, ReactiveList, AIAnswer } from "@appbaseio/reactivesearch";
3 |
4 | import { booksList as BooksList } from "./resultViews";
5 |
6 | export default class AIAnswerxDefault extends Component {
7 | render() {
8 | return (
9 |
20 |
25 |
26 |
27 |
28 |
29 |
40 | {({ data }) => (
41 |
42 | {
43 | data.map(item => )
44 | }
45 |
46 | )}
47 |
48 |
49 |
57 |
58 |
59 | );
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/stories/reactivemaps/ReactiveGoogleMap.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import {
3 | ReactiveBase,
4 | SingleList,
5 | } from "@appbaseio/reactivesearch";
6 |
7 | import { ReactiveGoogleMap } from '@appbaseio/reactivemaps';
8 |
9 | import historyPin from "./placeholder.png";
10 |
11 | export default class ReactiveGoogleMapDefault extends Component {
12 | constructor(props) {
13 | super(props);
14 | this.onPopoverClick = this.onPopoverClick.bind(this);
15 | }
16 |
17 | onPopoverClick(marker) {
18 | return (
19 |
20 | Earthquake (at) {marker.place}
21 | of maginutde: {marker.mag} in the year {marker.time}.
22 |
23 |
);
24 | }
25 |
26 | render() {
27 | return (
28 |
34 |
35 |
46 |
47 |
({
56 | label: result.mag,
57 | // icon: 'https://i.imgur.com/NHR2tYL.png',
58 | // custom: ({result.mag}
),
59 | })}
60 | defaultCenter={{
61 | lat: -23.944,
62 | lng: -70.093,
63 | }}
64 | react={{
65 | and: ["CitySensor", "VenueSensor"]
66 | }}
67 | {...this.props}
68 | />
69 |
70 |
71 |
72 | );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/stories/reactivemaps/ReactiveOpenStreetMapDefault.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import {
3 | ReactiveBase,
4 | SingleList,
5 | } from "@appbaseio/reactivesearch";
6 |
7 | import { ReactiveOpenStreetMap } from '@appbaseio/reactivemaps';
8 |
9 | import { Img } from "./Img.js";
10 | import historyPin from "./placeholder.png";
11 |
12 | export default class ReactiveOpenStreetMapDefault extends Component {
13 | constructor(props) {
14 | super(props);
15 | this.onPopoverClick = this.onPopoverClick.bind(this);
16 | }
17 |
18 | onPopoverClick(marker) {
19 | return (
20 |
21 | Earthquake (at) {marker.place}
22 | of maginutde: {marker.mag} in the year {marker.time}.
23 |
24 |
);
25 | }
26 |
27 | render() {
28 | return (
29 |
35 |
36 |
47 |
48 |
({
57 | label: result.mag,
58 | // icon: 'https://i.imgur.com/NHR2tYL.png',
59 | // custom: ({result.mag}
),
60 | })}
61 | defaultCenter={{
62 | lat: -23.944,
63 | lng: -70.093,
64 | }}
65 | react={{
66 | and: ["CitySensor", "VenueSensor"]
67 | }}
68 | {...this.props}
69 | />
70 |
71 |
72 |
73 | );
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/stories/reactivesearch/TreeList.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, TreeList, SelectedFilters, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksList as BooksList } from "./resultViews";
5 |
6 | export default class TreeListDefault extends Component {
7 | booksReactiveList(data) {
8 | return (
9 |
10 |
11 |
12 |
{data.name}
13 |
14 |
15 |
16 | {data.class} > {data.subclass}
17 |
18 |
19 | Sale price: {data.salePrice}
20 |
21 |
22 |
23 |
24 |
25 | );
26 | }
27 |
28 | render() {
29 | return (
30 |
35 |
36 |
37 |
38 |
50 |
51 |
52 |
71 |
72 |
73 |
74 | );
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/stories/reactivesearch/MultiListWithIndexProp.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, SelectedFilters, MultiList, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksReactiveList } from "./resultViews";
5 |
6 | export default class MultiListDefault extends Component {
7 | render() {
8 | return (
9 |
14 |
15 |
16 |
17 | {/* all queries triggereing from this component will be tragetted to the 'good-books-clone' index in the BE as it is specified
18 | through the index prop */}
19 |
32 |
33 |
34 | {/* as no index is specified in this component, by default all the queries made will be targetted to the
35 | index provided in seachbase component */}
36 |
48 |
49 |
50 |
51 |
52 |
53 |
64 |
65 |
66 |
67 | );
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/stories/reactivemaps/GeoDistanceDropDownOpenStreetMap.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import {
3 | ReactiveBase,
4 | SelectedFilters,
5 | } from '@appbaseio/reactivesearch';
6 | import {
7 | ReactiveOpenStreetMap,
8 | GeoDistanceDropdown,
9 | } from "@appbaseio/reactivemaps";
10 |
11 | import { Img } from "./Img.js";
12 | import historyPin from "./placeholder.png";
13 |
14 | export default class GeoDistanceDropdownDefault extends Component {
15 | constructor(props) {
16 | super(props);
17 | // this.onPopoverTrigger = this.onPopoverTrigger.bind(this);
18 | }
19 |
20 | onPopoverTrigger(marker) {
21 | return (
22 |
23 |
24 |
25 |
26 |
27 | {marker._source.member.member_name}
28 |
29 |
36 |
37 |
);
38 | }
39 |
40 | render() {
41 | return (
42 |
49 |
50 |
51 |
52 |
57 |
58 |
59 |
71 |
72 |
73 |
74 | );
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/stories/reactivemaps/GeoDistanceDropdownGoogleMap.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import {
3 | ReactiveBase,
4 | SelectedFilters,
5 | } from '@appbaseio/reactivesearch';
6 | import {
7 | ReactiveGoogleMap,
8 | GeoDistanceDropdown,
9 | } from "@appbaseio/reactivemaps";
10 |
11 | import { Img } from "./Img.js";
12 | import historyPin from "./placeholder.png";
13 |
14 | export default class GeoDistanceDropdownDefault extends Component {
15 | constructor(props) {
16 | super(props);
17 | // this.onPopoverTrigger = this.onPopoverTrigger.bind(this);
18 | }
19 |
20 | onPopoverTrigger(marker) {
21 | return (
22 |
23 |
24 |
25 |
26 |
27 | {marker._source.member.member_name}
28 |
29 |
36 |
37 |
);
38 | }
39 |
40 | render() {
41 | return (
42 |
49 |
50 |
51 |
52 |
57 |
58 |
59 |
73 |
74 |
75 |
76 | );
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/stories/reactivesearch/SearchBoxWithIndexProp.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, SearchBox, SelectedFilters, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksList as BooksList } from "./resultViews";
5 |
6 | export default class SearchBoxDefault extends Component {
7 | render() {
8 | return (
9 |
17 |
18 |
19 |
20 | {/* as no index is specified in this component, by default all the queries made will be targetted to the
21 | index provided in seachbase component */}
22 |
32 |
33 |
34 | {/* all queries triggereing from this component will be tragetted to the 'good-books-clone' index in the BE as it is specified
35 | through the index prop */}
36 |
47 |
48 |
49 |
50 |
61 | {({ data }) => (
62 |
63 | {
64 | data.map(item => )
65 | }
66 |
67 | )}
68 |
69 |
70 |
71 |
72 | );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/stories/reactivemaps/GeoDistanceSliderGoogleMap.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import {
3 | ReactiveBase,
4 | SelectedFilters,
5 | } from '@appbaseio/reactivesearch';
6 | import {
7 | ReactiveGoogleMap,
8 | GeoDistanceSlider,
9 | } from "@appbaseio/reactivemaps";
10 |
11 | import { Img } from "./Img.js";
12 | import historyPin from "./placeholder.png";
13 |
14 | export default class GeoDistanceSliderDefault extends Component {
15 | constructor(props) {
16 | super(props);
17 | // this.onPopoverTrigger = this.onPopoverTrigger.bind(this);
18 | }
19 |
20 | onPopoverTrigger(marker) {
21 | return (
22 |
23 |
24 |
25 |
26 |
27 | {marker._source.member.member_name}
28 |
29 |
36 |
37 |
);
38 | }
39 |
40 | render() {
41 | return (
42 |
49 |
50 |
51 |
52 |
61 |
62 |
63 |
77 |
78 |
79 |
80 | );
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/stories/reactivemaps/GeoDistanceSliderOpenStreetMap.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import {
3 | ReactiveBase,
4 | SelectedFilters,
5 | } from '@appbaseio/reactivesearch';
6 | import {
7 | ReactiveOpenStreetMap,
8 | GeoDistanceSlider,
9 | } from "@appbaseio/reactivemaps";
10 |
11 | import { Img } from "./Img.js";
12 | import historyPin from "./placeholder.png";
13 |
14 | export default class GeoDistanceSliderDefault extends Component {
15 | constructor(props) {
16 | super(props);
17 | // this.onPopoverTrigger = this.onPopoverTrigger.bind(this);
18 | }
19 |
20 | onPopoverTrigger(marker) {
21 | return (
22 |
23 |
24 |
25 |
26 |
27 | {marker._source.member.member_name}
28 |
29 |
36 |
37 |
);
38 | }
39 |
40 | render() {
41 | return (
42 |
49 |
50 |
51 |
52 |
61 |
62 |
63 |
77 |
78 |
79 |
80 | );
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/stories/reactivesearch/ReactiveComponentWithDistinctFieldProp.js:
--------------------------------------------------------------------------------
1 | /* eslint react/prop-types: 0 */
2 | import React, { Component } from 'react';
3 |
4 | import {
5 | ReactiveBase,
6 | ReactiveComponent,
7 | ReactiveList,
8 | SelectedFilters,
9 | } from '@appbaseio/reactivesearch';
10 |
11 | export default class ReactiveComponentDefault extends Component {
12 | renderItem(data) {
13 | return (
14 |
15 |
{data.name}
16 |
{data.price} - {data.rating} stars rated
17 |
18 | );
19 | }
20 | render() {
21 | return (
22 |
27 |
28 |
29 |
30 | ({
33 | aggs: {
34 | 'brand.keyword': {
35 | terms: {
36 | field: 'brand.keyword',
37 | order: {
38 | _count: 'desc',
39 | },
40 | size: 1,
41 | },
42 | },
43 | },
44 | })}
45 | distinctField="brand.keyword"
46 | distinctFieldConfig={{
47 | inner_hits: {
48 | name: 'most_recent',
49 | size: 5,
50 | sort: [{ timestamp: 'asc' }],
51 | },
52 | max_concurrent_group_searches: 4,
53 | }}
54 | size={10}
55 | {...this.props}
56 | >
57 | {({ data, setQuery }) => }
58 |
59 |
60 |
61 |
62 |
74 |
75 |
76 |
77 | );
78 | }
79 | }
80 |
81 | class CustomComponent extends Component {
82 | setValue(value) {
83 | this.props.setQuery({
84 | query: {
85 | term: {
86 | "brand.keyword": value,
87 | },
88 | },
89 | value,
90 | });
91 | }
92 |
93 | render() {
94 | if (this.props.data) {
95 | return this.props.data.map(item => (
96 | this.setValue(item.brand)}>{item.brand}
97 | ));
98 | }
99 | return null;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/stories/styles.css:
--------------------------------------------------------------------------------
1 | .row {
2 | display: flex;
3 | flex-direction: row;
4 | width: 100%;
5 | }
6 |
7 | .row.dark {
8 | background: #303030;
9 | }
10 |
11 | .col {
12 | width: calc(100% - 400px);
13 | padding: 15px;
14 | }
15 | .container{
16 | padding: 1.5rem;
17 | }
18 | .row > .col:first-child {
19 | border-right: 1px solid #ccc;
20 | max-width: 400px;
21 | }
22 |
23 | .result-list-container {
24 | max-width: 800px;
25 | }
26 |
27 | .row > .col:last-child {
28 | background: #fafafa;
29 | }
30 |
31 | .row.dark > .col:last-child {
32 | background: #303030;
33 | }
34 |
35 | .flex {
36 | display: flex;
37 | }
38 |
39 | .wrap {
40 | flex-wrap: wrap;
41 | }
42 |
43 | .column {
44 | flex-direction: column;
45 | }
46 |
47 | .authors-list {
48 | color: #9d9d9d;
49 | font-weight: bold;
50 | }
51 |
52 | .dark .authors-list {
53 | color: #fafafa;
54 | }
55 |
56 | .ratings-list {
57 | padding: 10px 0;
58 | }
59 |
60 | .avg-rating {
61 | color: #6b6b6b;
62 | margin-left: 5px;
63 | }
64 |
65 | .dark .avg-rating {
66 | color: #fafafa;
67 | }
68 |
69 | .align-center {
70 | align-items: center;
71 | }
72 |
73 | .justify-center {
74 | justify-content: center;
75 | }
76 |
77 | .justify-space-between {
78 | justify-content: space-between;
79 | }
80 |
81 | .stars {
82 | color: gold;
83 | }
84 |
85 | .location {
86 | color: salmon;
87 | margin-right: 5px;
88 | }
89 |
90 | .meetup-location {
91 | margin: 4px 0;
92 | }
93 |
94 | .book-title {
95 | white-space: normal;
96 | margin-top: 4px;
97 | }
98 |
99 | .book-title-card {
100 | white-space: normal;
101 | margin-top: 4px;
102 | max-height: 45px;
103 | }
104 |
105 | .book-image {
106 | height: 150px;
107 | width: 110px;
108 | background-size: cover;
109 | }
110 |
111 | .book-header {
112 | font-weight: bold;
113 | margin-bottom: 5px;
114 | }
115 |
116 | .book-content {
117 | background: white;
118 | margin: 10px 0;
119 | box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
120 | }
121 |
122 | .meetup-title {
123 | white-space: normal;
124 | }
125 |
126 | .meetup-topics {
127 | height: 35px;
128 | overflow: hidden;
129 | }
130 |
131 | .text-center {
132 | text-align: center;
133 | }
134 |
135 | .meetup-topic {
136 | background-color: #dedede;
137 | color: #555;
138 | padding: 5px 10px;
139 | margin: 5px;
140 | border-radius: 4px;
141 | }
142 |
143 | .meetup-topic:first-child {
144 | margin-left: 0;
145 | }
146 |
147 | .col .meetup-list-image {
148 | background-size: cover;
149 | }
150 |
151 | .recent-icon {
152 | height: 20px;
153 | width: 20px;
154 | fill: royalblue;
155 | }
156 | .popular-icon {
157 | height: 20px;
158 | width: 20px;
159 | fill: rgb(253, 44, 16);
160 | }
161 |
--------------------------------------------------------------------------------
/stories/reactivesearch/DarkCard.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, NumberBox, RangeInput, SelectedFilters, SingleDropdownRange, MultiDropdownRange, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksCard as BooksCard } from "./resultViews";
5 |
6 | export default class ResultCardDefault extends Component {
7 | render() {
8 | return (
9 |
15 |
16 |
17 |
18 |
19 |
29 |
30 |
43 |
44 | 4" }]
52 | }
53 | />
54 |
55 | 4" }]
63 | }
64 | />
65 |
66 |
72 |
83 | {
84 | ({ data }) => (
85 |
86 | {
87 | data.map(item => )
88 | }
89 |
90 | )
91 | }
92 |
93 |
94 |
95 |
96 | );
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/stories/reactivesearch/ReactiveComponent.stories.js:
--------------------------------------------------------------------------------
1 | /* eslint react/prop-types: 0 */
2 | import React, { Component } from 'react';
3 |
4 | import {
5 | ReactiveBase,
6 | ReactiveComponent,
7 | ReactiveList,
8 | SelectedFilters,
9 | } from '@appbaseio/reactivesearch';
10 |
11 | export default class ReactiveComponentDefault extends Component {
12 | renderItem(data) {
13 | return (
14 |
15 |
{data.name}
16 |
{data.price} - {data.rating} stars rated
17 |
18 | );
19 | }
20 | triggerRef = React.createRef(null);
21 | render() {
22 | return (
23 |
28 | {this.test}
29 |
30 |
31 | {
32 | if (props === 'CarSensor' && this.triggerRef.current) {
33 | this.triggerRef.current({
34 | query: {
35 | "match_all": {}
36 | },
37 | value: null
38 | });
39 | }
40 | ref={testRef} // testRef.current would hold the ref of SelectedFitlers
41 |
42 | }} />
43 | ({
46 | aggs: {
47 | 'brand.keyword': {
48 | terms: {
49 | field: 'brand.keyword',
50 | order: {
51 | _count: 'desc',
52 | },
53 | size: 10,
54 | },
55 | },
56 | },
57 | })}
58 | {...this.props}
59 | >
60 | {({ aggregations, setQuery }) => {
61 | if (!this.triggerRef.current) {
62 | this.triggerRef.current = setQuery;
63 | }
64 | return
65 | }}
66 |
67 |
68 |
69 |
70 |
82 |
83 |
84 |
85 | );
86 | }
87 | }
88 |
89 | class CustomComponent extends Component {
90 | setValue(value) {
91 | this.props.setQuery({
92 | query: {
93 | term: {
94 | "brand.keyword": value,
95 | },
96 | },
97 | value,
98 | });
99 | }
100 |
101 | render() {
102 | if (this.props.aggregations) {
103 | return this.props.aggregations['brand.keyword'].buckets.map(item => (
104 | this.setValue(item.key)}>{item.key}
105 | ));
106 | }
107 | return null;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/stories/reactivesearch/TagCloudDark.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, TagCloud, SingleDataList, MultiDataList, ToggleButton, ReactiveList, SelectedFilters } from "@appbaseio/reactivesearch";
3 |
4 | import { meetupList as MeetupList } from "./resultViews";
5 |
6 | export default class TagCloudDefault extends Component {
7 | render() {
8 | return (
9 |
15 |
16 |
17 |
27 |
28 |
39 |
40 |
51 |
52 |
58 |
59 |
60 |
61 |
78 | {({ data }) => (
79 |
80 | {
81 | data.map(item => )
82 | }
83 |
84 | )}
85 |
86 |
87 |
88 |
89 | );
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/stories/reactivesearch/TabDataList.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, ReactiveList, SelectedFilters, TabDataList } from "@appbaseio/reactivesearch";
3 |
4 | import { meetupList as MeetupList } from "./resultViews";
5 |
6 | const HorizontalLayout = (props) =>(
7 |
8 |
9 |
20 |
34 | {({ data }) => (
35 |
36 | {
37 | data.map(item => )
38 | }
39 |
40 | )}
41 |
42 |
43 | )
44 |
45 | const VerticalLayout = (props)=>(
46 | <>
47 |
48 |
49 |
50 |
61 |
62 |
63 |
77 | {({ data }) => (
78 |
79 | {
80 | data.map(item => )
81 | }
82 |
83 | )}
84 |
85 |
86 |
87 | >
88 | )
89 |
90 | export default class TabDataListDefault extends Component {
91 | render() {
92 | return (
93 |
98 | {this.props.displayAsVertical ? : }
99 |
100 | );
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/stories/reactivesearch/DatePickerDark.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import moment from "moment";
3 | import {
4 | ReactiveBase,
5 | DatePicker,
6 | ReactiveList,
7 | SelectedFilters,
8 | ResultCard,
9 | } from "@appbaseio/reactivesearch";
10 | import ResponsiveStory from "./ResponsiveStory";
11 |
12 | export default class DatePickerDefault extends Component {
13 | componentDidMount() {
14 | ResponsiveStory();
15 | }
16 |
17 | dateQuery(value, props) {
18 | let query = null;
19 | if (value) {
20 | query = [
21 | {
22 | range: {
23 | [props.dataField]: {
24 | lte: moment(value).valueOf(),
25 | },
26 | },
27 | },
28 | ];
29 | }
30 | return query ? { query: { bool: { must: query } } } : null;
31 | }
32 |
33 | render() {
34 | return (
35 |
41 |
42 |
43 |
51 |
52 |
53 |
54 |
55 |
66 | {({ data }) => (
67 |
68 | {data.map((item) => (
69 |
70 |
71 |
74 |
75 |
76 |
${item.price}
77 |
82 |
83 | {item.room_type} · {item.accommodates} guests
84 |
85 |
86 |
87 |
88 | ))}
89 |
90 | )}
91 |
92 |
93 |
94 |
95 | );
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/stories/reactivesearch/DatePicker.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import moment from "moment";
3 | import {
4 | ReactiveBase,
5 | DatePicker,
6 | ReactiveList,
7 | SelectedFilters,
8 | ResultCard,
9 | } from "@appbaseio/reactivesearch";
10 | import ResponsiveStory from "./ResponsiveStory";
11 |
12 | export default class DatePickerDefault extends Component {
13 | componentDidMount() {
14 | ResponsiveStory();
15 | }
16 |
17 | dateQuery(value, props) {
18 | let query = null;
19 | if (value) {
20 | query = [
21 | {
22 | range: {
23 | [props.dataField]: {
24 | lte: moment(value).valueOf(),
25 | },
26 | },
27 | },
28 | ];
29 | }
30 | return query ? { query: { bool: { must: query } } } : null;
31 | }
32 |
33 | render() {
34 | return (
35 |
41 |
42 |
43 |
52 |
53 |
54 |
55 |
56 |
66 | {({ data }) => (
67 |
68 | {data.map((item) => (
69 |
70 |
71 |
76 |
77 |
78 |
${item.price}
79 |
84 |
85 | {item.room_type} · {item.accommodates} guests
86 |
87 |
88 |
89 |
90 | ))}
91 |
92 | )}
93 |
94 |
95 |
96 |
97 | );
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/stories/reactivesearch/ReactiveElement/WithStream.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, MultiList, ReactiveElement } from "@appbaseio/reactivesearch";
3 | import { AppbaseSensorHelper as helper } from "@appbaseio/reactivesearch";
4 | import ResponsiveStory from "../ResponsiveStory";
5 | import { GetTopTopics } from "./helper";
6 | import { Img } from "../Img.js";
7 |
8 | require("../list.css");
9 |
10 | export default class WithStream extends Component {
11 | constructor(props) {
12 | super(props);
13 | this.cityQuery = this.cityQuery.bind(this);
14 | this.onAllData = this.onAllData.bind(this);
15 | this.DEFAULT_IMAGE = "http://www.avidog.com/wp-content/uploads/2015/01/BellaHead082712_11-50x65.jpg";
16 | }
17 |
18 | cityQuery(value) {
19 | if (value) {
20 | const field = "group.group_city.group_city_simple";
21 | const query = JSON.parse(`{"${field}":${JSON.stringify(value)}}`);
22 | return { terms: query };
23 | } return null;
24 | }
25 |
26 | componentDidMount() {
27 | ResponsiveStory();
28 | }
29 |
30 | onAllData(res, err) {
31 | let result = null;
32 | if (res && res.appliedQuery) {
33 | let combineData = res.currentData;
34 | if (res.mode === "historic") {
35 | combineData = res.currentData.concat(res.newData);
36 | } else if (res.mode === "streaming") {
37 | combineData = helper.combineStreamData(res.currentData, res.newData);
38 | }
39 | if (combineData) {
40 | combineData = GetTopTopics(combineData);
41 | const resultMarkup = combineData.map((data, index) => {
42 | if (index < 5) {
43 | return this.itemMarkup(data, index);
44 | }
45 | });
46 | result = (
47 |
48 |
49 |
50 | {resultMarkup}
51 |
52 |
53 |
54 | );
55 | }
56 | }
57 | return result;
58 | }
59 |
60 | itemMarkup(data, index) {
61 | return (
62 |
63 | {data.name}
64 | {data.value}
65 |
66 | );
67 | }
68 |
69 |
70 | render() {
71 | return (
72 |
77 |
78 |
79 |
92 |
93 |
94 |
95 |
107 |
108 |
109 |
110 | );
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/stories/reactivesearch/ReactiveElement/WithTheme.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, MultiList, ReactiveElement } from "@appbaseio/reactivesearch";
3 | import { AppbaseSensorHelper as helper } from "@appbaseio/reactivesearch";
4 | import ResponsiveStory from "../ResponsiveStory";
5 | import { GetTopTopics } from "./helper";
6 | import { Img } from "../Img.js";
7 |
8 | require("../list.css");
9 |
10 | export default class WithTheme extends Component {
11 | constructor(props) {
12 | super(props);
13 | this.cityQuery = this.cityQuery.bind(this);
14 | this.onAllData = this.onAllData.bind(this);
15 | this.DEFAULT_IMAGE = "http://www.avidog.com/wp-content/uploads/2015/01/BellaHead082712_11-50x65.jpg";
16 | }
17 |
18 | cityQuery(value) {
19 | if (value) {
20 | const field = "group.group_city.group_city_simple";
21 | const query = JSON.parse(`{"${field}":${JSON.stringify(value)}}`);
22 | return { terms: query };
23 | } return null;
24 | }
25 |
26 | componentDidMount() {
27 | ResponsiveStory();
28 | }
29 |
30 | onAllData(res, err) {
31 | let result = null;
32 | if (res && res.appliedQuery) {
33 | let combineData = res.currentData;
34 | if (res.mode === "historic") {
35 | combineData = res.currentData.concat(res.newData);
36 | } else if (res.mode === "streaming") {
37 | combineData = helper.combineStreamData(res.currentData, res.newData);
38 | }
39 | if (combineData) {
40 | combineData = GetTopTopics(combineData);
41 | const resultMarkup = combineData.map((data, index) => {
42 | if (index < 5) {
43 | return this.itemMarkup(data, index);
44 | }
45 | });
46 | result = (
47 |
48 |
49 |
50 | {resultMarkup}
51 |
52 |
53 |
54 | );
55 | }
56 | }
57 | return result;
58 | }
59 |
60 | itemMarkup(data, index) {
61 | return (
62 |
63 | {data.name}
64 | {data.value}
65 |
66 | );
67 | }
68 |
69 |
70 | render() {
71 | return (
72 |
78 |
79 |
80 |
92 |
93 |
94 |
95 |
107 |
108 |
109 |
110 | );
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/stories/reactivesearch/DateRange.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import moment from "moment";
3 | import {
4 | ReactiveBase,
5 | DateRange,
6 | ResultCard,
7 | ReactiveList,
8 | SelectedFilters,
9 | } from "@appbaseio/reactivesearch";
10 | import ResponsiveStory from "./ResponsiveStory";
11 |
12 | export default class DateRangeDefault extends Component {
13 | componentDidMount() {
14 | ResponsiveStory();
15 | }
16 |
17 | dateQuery(value) {
18 | let query = null;
19 | if (value) {
20 | query = [
21 | {
22 | range: {
23 | available_from: {
24 | gte: moment(value.start).valueOf(),
25 | },
26 | },
27 | },
28 | {
29 | range: {
30 | available_to: {
31 | lte: moment(value.end).valueOf(),
32 | },
33 | },
34 | },
35 | ];
36 | }
37 | return query ? { query: { bool: { must: query } } } : null;
38 | }
39 |
40 | render() {
41 | return (
42 |
47 |
48 |
49 |
58 |
59 |
60 |
61 |
62 |
72 | {({ data }) => (
73 |
74 | {data.map((item) => (
75 |
76 |
77 |
82 |
83 |
84 |
${item.price}
85 |
90 |
91 | {item.room_type} · {item.accommodates} guests
92 |
93 |
94 |
95 |
96 | ))}
97 |
98 | )}
99 |
100 |
101 |
102 |
103 | );
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/stories/reactivesearch/DateRangeDark.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import moment from "moment";
3 | import {
4 | ReactiveBase,
5 | DateRange,
6 | ResultCard,
7 | SelectedFilters,
8 | ReactiveList,
9 | } from "@appbaseio/reactivesearch";
10 | import ResponsiveStory from "./ResponsiveStory";
11 |
12 | export default class DateRangeDefault extends Component {
13 | componentDidMount() {
14 | ResponsiveStory();
15 | }
16 |
17 | dateQuery(value) {
18 | let query = null;
19 | if (value) {
20 | query = [
21 | {
22 | range: {
23 | available_from: {
24 | gte: moment(value.start).valueOf(),
25 | },
26 | },
27 | },
28 | {
29 | range: {
30 | available_to: {
31 | lte: moment(value.end).valueOf(),
32 | },
33 | },
34 | },
35 | ];
36 | }
37 | return query ? { query: { bool: { must: query } } } : null;
38 | }
39 |
40 | render() {
41 | return (
42 |
48 |
49 |
50 |
58 |
59 |
60 |
61 |
62 |
73 | {({ data }) => (
74 |
75 | {data.map((item) => (
76 |
77 |
78 |
83 |
84 |
85 |
${item.price}
86 |
91 |
92 | {item.room_type} · {item.accommodates} guests
93 |
94 |
95 |
96 |
97 | ))}
98 |
99 | )}
100 |
101 |
102 |
103 |
104 | );
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/stories/reactivesearch/list.css:
--------------------------------------------------------------------------------
1 | #map,
2 | .h-100,
3 | body,
4 | html {
5 | height: 100%;
6 | }
7 |
8 | .rbc-base > .row {
9 | position: absolute;
10 | width: 100%;
11 | height: 100%;
12 | }
13 |
14 | .rbc-base > .row > .col.s6 {
15 | position: relative;
16 | height: 100%;
17 | }
18 |
19 | .rbc-base > .row > .col.s6:first-child {
20 | border-right: 1px solid #cdcdcd;
21 | }
22 |
23 | .rbc-base > .row > .col.s6:first-child::after,
24 | .rbc-base > .row > .col.s6:last-child::after {
25 | content: 'Actuator';
26 | display: block;
27 | position: absolute;
28 | text-align: center;
29 | color: #fff;
30 | font-size: 12px;
31 | letter-spacing: 0.04em;
32 | top: 0;
33 | right: 0;
34 | padding: 2px 10px;
35 | text-transform: uppercase;
36 | background-color: #bcbcbc;
37 | border-bottom-left-radius: 5px;
38 | }
39 |
40 | .rbc-base > .row > .col.s6:first-child::after {
41 | content: 'Sensor';
42 | }
43 |
44 | .rbc-base > .row.reverse-labels > .col.s6:first-child::after {
45 | content: 'Actuator';
46 | }
47 |
48 | .rbc-base > .row.reverse-labels > .col.s6:last-child::after {
49 | content: 'Sensor';
50 | }
51 |
52 | .listResult {
53 | height: 100%;
54 | position: relative;
55 | padding: 0;
56 | margin: 0;
57 | overflow: auto;
58 | }
59 |
60 | .makerInfo {
61 | margin-bottom: 15px;
62 | font-size: 12px;
63 | }
64 |
65 | .full_row {
66 | display: block;
67 | width: 100%;
68 | position: relative;
69 | }
70 |
71 | .single-record {
72 | height: 70px;
73 | }
74 |
75 | .single-record .img-container {
76 | position: absolute;
77 | left: 10px;
78 | top: 10px;
79 | width: 50px;
80 | height: 50px;
81 | overflow: hidden;
82 | border-radius: 8px;
83 | }
84 |
85 | .img-container img {
86 | width: 100%;
87 | }
88 |
89 | .single-record .text-container {
90 | padding-left: 70px;
91 | padding-top: 10px;
92 | font-size: 16px;
93 | line-height: 25px
94 | }
95 |
96 | .single-record .text-description {
97 | color: #aaa
98 | }
99 |
100 | .text-overflow {
101 | overflow: hidden;
102 | text-overflow: ellipsis;
103 | white-space: nowrap;
104 | }
105 |
106 | .highlight_tags {
107 | display: block;
108 | float: left;
109 | padding-left: 0;
110 | list-style-position: inside;
111 | overflow: hidden;
112 | max-height: 24px;
113 | margin: 0;
114 | }
115 |
116 | .highlight_tags li {
117 | float: left;
118 | padding-right: 10px;
119 | }
120 |
121 | .text-head-city {
122 | position: absolute;
123 | right: 10px;
124 | top: 0;
125 | font-size: 12px;
126 | line-height: 25px;
127 | color: #aaa;
128 | font-weight: bold;
129 | }
130 |
131 | .text-head-info {
132 | display: block;
133 | width: 100%;
134 | padding-right: 100px;
135 | position: relative;
136 | }
137 |
138 | .single-record .text-description {
139 | position: relative;
140 | padding-right: 100px;
141 | }
142 | .single-record .sort-info {
143 | position: absolute;
144 | right: 5px;
145 | font-size: 10px;
146 | }
147 |
148 | .rbc-highlight-table th, .rbc-highlight-table td{
149 | padding: 5px;
150 | vertical-align: top;
151 | }
152 |
153 | .rbc-highlight-table th {
154 | font-weight: lighter;
155 | color: #aaa;
156 | }
157 |
158 | .animate {
159 | -webkit-animation: fadein 2s; /* Safari, Chrome and Opera > 12.1 */
160 | -moz-animation: fadein 2s; /* Firefox < 16 */
161 | -ms-animation: fadein 2s; /* Internet Explorer */
162 | -o-animation: fadein 2s; /* Opera < 12.1 */
163 | animation: fadein 2s;
164 | }
165 |
166 | @keyframes fadein {
167 | from { opacity: 0; }
168 | to { opacity: 1; }
169 | }
170 |
171 | /* Firefox < 16 */
172 | @-moz-keyframes fadein {
173 | from { opacity: 0; }
174 | to { opacity: 1; }
175 | }
176 |
177 | /* Safari, Chrome and Opera > 12.1 */
178 | @-webkit-keyframes fadein {
179 | from { opacity: 0; }
180 | to { opacity: 1; }
181 | }
182 |
183 | /* Internet Explorer */
184 | @-ms-keyframes fadein {
185 | from { opacity: 0; }
186 | to { opacity: 1; }
187 | }
188 |
189 | /* Opera < 12.1 */
190 | @-o-keyframes fadein {
191 | from { opacity: 0; }
192 | to { opacity: 1; }
193 | }
194 |
--------------------------------------------------------------------------------
/stories/reactivesearch/resultViews/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ResultCard, ResultList } from '@appbaseio/reactivesearch';
3 |
4 | export const booksList = (data) => (
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
by {data.authors}
15 |
16 |
17 | {
18 | Array(data.average_rating_rounded).fill('x')
19 | .map((item, index) => )
20 | }
21 |
22 | ({data.average_rating} avg)
23 |
24 |
25 |
Pub {data.original_publication_year}
26 |
27 |
28 |
29 |
30 | );
31 |
32 | export const booksCard = (data) => (
33 |
34 |
35 |
36 |
37 |
38 |
39 |
by {data.authors}
40 |
41 |
42 | {
43 | Array(data.average_rating_rounded).fill('x')
44 | .map((item, index) => ) // eslint-disable-line
45 | }
46 |
47 | ({data.average_rating} avg)
48 |
49 |
50 |
Pub {data.original_publication_year}
51 |
52 |
53 |
54 | );
55 |
56 | export const booksReactiveList = (data) => (
57 |
58 |
59 |
60 |
{data.original_title}
61 |
62 |
63 |
by {data.authors}
64 |
65 |
66 | {
67 | Array(data.average_rating_rounded).fill('x')
68 | .map((item, index) => ) // eslint-disable-line
69 | }
70 |
71 | ({data.average_rating} avg)
72 |
73 |
74 |
Pub {data.original_publication_year}
75 |
76 |
77 |
78 | );
79 |
80 | export const meetupList = (data) => (
81 |
82 |
83 |
84 |
85 |
86 | {data.member ? data.member.member_name : ""} is going to ${data.event ? data.event.event_name : ""}
87 |
88 |
89 |
90 |
91 |
92 |
93 | {data.group ? data.group.group_city : ""}
94 |
95 |
96 | {
97 | data.group.group_topics.slice(0, 4).map(tag => (
98 |
{tag.topic_name}
99 | ))
100 | }
101 |
102 |
103 |
104 |
105 |
106 | )
107 |
--------------------------------------------------------------------------------
/stories/reactivesearch/TreeListCustomRenderer.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, TreeList, SelectedFilters, ReactiveList } from "@appbaseio/reactivesearch";
3 |
4 | import { booksList as BooksList } from "./resultViews";
5 | const recLookup = (obj, path) => {
6 | try {
7 | const parts = path.split('.');
8 | if (parts.length === 1) {
9 | return obj[parts[0]];
10 | }
11 | return recLookup(obj[parts[0]], parts.slice(1).join('.'));
12 | } catch (e) {
13 | return false;
14 | }
15 | };
16 | export default class TreeListCustomRenderer extends Component {
17 | booksReactiveList(data) {
18 | return (
19 |
20 |
21 |
22 |
{data.name}
23 |
24 |
25 |
26 | {data.class} > {data.subclass}
27 |
28 |
29 | Sale price: {data.salePrice}
30 |
31 |
32 |
33 |
34 |
35 | );
36 | }
37 |
38 | renderListItems(listItem, parentPath, selectedValues, handleListItemClick) {
39 | if (!(listItem instanceof Object) || Object.keys(listItem).length === 0) {
40 | return null;
41 | }
42 | const listItemLabel = listItem.key;
43 | const listItemCount = listItem.count;
44 | const isLeafNode = !(Array.isArray(listItem.list) && listItem.list.length > 0);
45 |
46 | let newParentPath = listItemLabel;
47 | if (parentPath) {
48 | newParentPath = `${parentPath}.${listItemLabel}`;
49 | }
50 | const isSelected = recLookup(selectedValues, newParentPath);
51 |
52 | return (
53 |
54 | {/* eslint-disable jsx-a11y/click-events-have-key-events */}
55 | {/* eslint-disable jsx-a11y/no-static-element-interactions */}
56 | handleListItemClick(listItemLabel, parentPath)}
59 | >
60 |
61 | {listItemLabel}
62 |
63 | {listItemCount}
64 |
65 |
66 | {isLeafNode === false && (
67 |
68 | {/* eslint-disable-next-line no-use-before-define */}
69 | {this.renderLists(
70 | listItem.list,
71 | newParentPath,
72 | isSelected,
73 | selectedValues,
74 | handleListItemClick,
75 | )}
76 |
77 | )}
78 |
79 | );
80 | }
81 |
82 | renderLists(transformedData, parentPath, isExpanded, selectedValues, handleClick) {
83 | return (
84 |
85 | {transformedData.map(listItem =>
86 | this.renderListItems(listItem, parentPath, selectedValues, handleClick),
87 | )}
88 |
89 | );
90 | }
91 |
92 | render() {
93 | return (
94 |
99 |
100 |
101 |
102 | {
113 | const {
114 | /* eslint-disable no-unused-vars */
115 | data,
116 | rawData,
117 | error,
118 | handleClick,
119 | value,
120 | loading,
121 | } = propData;
122 | return this.renderLists(data, '', true, value, handleClick);
123 | }}
124 | {...this.props}
125 | />
126 |
127 |
128 |
147 |
148 |
149 |
150 | );
151 | }
152 |
153 | }
154 |
--------------------------------------------------------------------------------
/stories/reactivesearch/TreeListCustomSelectedFilters.stories.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable jsx-a11y/no-static-element-interactions */
2 | /* eslint-disable jsx-a11y/click-events-have-key-events */
3 | import React, { Component } from 'react';
4 |
5 | import {
6 | ReactiveBase,
7 | TreeList,
8 | ReactiveList,
9 | SelectedFilters,
10 | componentTypes,
11 | } from '@appbaseio/reactivesearch';
12 |
13 |
14 | class TreeListCustomSelectedFilters extends Component {
15 | render() {
16 | return (
17 |
22 |
23 |
24 |
37 |
38 |
39 |
40 |
{
42 | const { selectedValues, setValue } = props;
43 | const clearFilter = (component) => {
44 | setValue(component, null);
45 | };
46 |
47 | const filters = Object.keys(selectedValues).map((component) => {
48 | if (!selectedValues[component].value) return null;
49 |
50 | if (
51 | selectedValues[component].componentType
52 | === componentTypes.treeList
53 | ) {
54 | const { value } = selectedValues[component];
55 | const valueArray = value;
56 |
57 | return (
58 |
65 | {valueArray.map((valueItem, index) => {
66 | const pathParts = valueItem.split(' > ');
67 | return (
68 |
74 | {pathParts.map(
75 | (pathItem, pathItemIndex) => (
76 | {
78 | const newValueArray = [
79 | ...valueArray,
80 | ];
81 | newValueArray[index]
82 | = pathParts.length
83 | === 1
84 | ? ''
85 | : pathParts
86 | .slice(
87 | 0,
88 | pathItemIndex
89 | + 1,
90 | )
91 | .join(
92 | ' > ',
93 | );
94 | if (JSON.stringify(newValueArray) === JSON.stringify(valueArray)) {
95 | return;
96 | }
97 | setValue(
98 | component,
99 | newValueArray.filter(
100 | item =>
101 | !!item,
102 | ),
103 | );
104 | }}
105 | >
106 | {pathItem} {' '}
107 | {pathItemIndex
108 | !== pathParts.length - 1 ? (
109 |
114 | ➤
115 |
116 | ) : (
117 | ''
118 | )}
119 |
120 | ),
121 | )}
122 |
123 | );
124 | })}
125 |
126 | );
127 | }
128 |
129 | return (
130 | clearFilter(component)}
133 | >
134 | {selectedValues[component].value}
135 |
136 | );
137 | });
138 |
139 | return filters;
140 | }}
141 | />
142 | ({
153 | track_total_hits: true,
154 | })}
155 | includeFields={['class', 'subclass', 'name', 'image', 'salePrice']}
156 | />
157 |
158 |
159 |
160 | );
161 | }
162 |
163 | reactiveList(data) {
164 | return (
165 |
166 |
167 |
168 |
{data.name}
169 |
170 |
171 |
172 |
173 | {data.class} > {data.subclass}
174 |
175 |
176 |
177 | Sale Price 💰 {data.salePrice}
178 |
179 |
180 |
181 |
182 |
183 | );
184 | }
185 | }
186 |
187 |
188 | export default TreeListCustomSelectedFilters;
189 |
--------------------------------------------------------------------------------
/examples/KNNSearch/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import {
3 | ReactiveBase,
4 | SearchBox,
5 | MultiList,
6 | ReactiveList,
7 | } from "@appbaseio/reactivesearch";
8 | import styled from "@emotion/styled";
9 | import { FaUsers, FaBuilding } from "react-icons/fa";
10 |
11 | const Container = styled.div`
12 | max-width: 1000px;
13 | margin: 0 auto;
14 | padding: 2rem;
15 | font-family: Arial, sans-serif;
16 | `;
17 |
18 | const Layout = styled.div`
19 | display: flex;
20 | gap: 2rem;
21 | `;
22 |
23 | const FacetContainer = styled.div`
24 | width: 250px;
25 | `;
26 |
27 | const ResultsContainer = styled.div`
28 | flex: 1;
29 | `;
30 |
31 | const ResultItem = styled.div`
32 | display: flex;
33 | align-items: flex-start;
34 | padding: 1rem 0;
35 | border-bottom: 1px solid #ddd;
36 | `;
37 |
38 | const Logo = styled.img`
39 | width: 50px;
40 | height: 50px;
41 | object-fit: contain;
42 | margin-right: 1rem;
43 | `;
44 |
45 | const Info = styled.div`
46 | flex: 1;
47 | `;
48 |
49 | const CompanyName = styled.h3`
50 | margin: 0;
51 | font-size: 1.25rem;
52 | `;
53 |
54 | const OneLiner = styled.p`
55 | margin: 0.5rem 0;
56 | display: -webkit-box;
57 | -webkit-line-clamp: 2;
58 | -webkit-box-orient: vertical;
59 | overflow: hidden;
60 | `;
61 |
62 | const Meta = styled.div`
63 | display: flex;
64 | gap: 1rem;
65 | font-size: 0.9rem;
66 | color: #555;
67 | `;
68 |
69 | const Tags = styled.div`
70 | margin: 0.5rem 0;
71 | `;
72 |
73 | const Tag = styled.span`
74 | background-color: #f0f0f0;
75 | border-radius: 4px;
76 | padding: 0.25rem 0.5rem;
77 | margin-right: 0.5rem;
78 | `;
79 |
80 | const Link = styled.a`
81 | color: #007bff;
82 | text-decoration: none;
83 | &:hover {
84 | text-decoration: underline;
85 | }
86 | `;
87 |
88 | const KNNWithFaceting = () => {
89 | return (
90 |
95 |
96 | K-Nearest Neighbors Search with Facets
97 |
106 |
107 |
108 |
119 |
120 |
121 | (
142 | <>
143 | {data.map((item) => {
144 | const company = item._source || item;
145 | return (
146 |
147 |
151 |
152 | {company.name}
153 |
154 | {company.one_liner || company.long_description}
155 |
156 |
157 |
158 | {company.team_size}
159 |
160 |
161 | {company.stage}
162 |
163 |
164 |
165 | {company.industries &&
166 | company.industries.map((ind) => (
167 | {ind}
168 | ))}
169 |
170 |
175 | Visit website
176 |
177 |
178 |
179 | );
180 | })}
181 | >
182 | )}
183 | renderNoResults={() => No results found
}
184 | />
185 |
186 |
187 |
188 |
189 | );
190 | };
191 |
192 | export default KNNWithFaceting;
--------------------------------------------------------------------------------
/stories/reactivesearch/KNNSearch.stories.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import {
3 | ReactiveBase,
4 | SearchBox,
5 | MultiList,
6 | ReactiveList,
7 | } from "@appbaseio/reactivesearch";
8 | import styled from "@emotion/styled";
9 | import { FaUsers, FaBuilding } from "react-icons/fa";
10 |
11 | const Container = styled.div`
12 | max-width: 1000px;
13 | margin: 0 auto;
14 | padding: 2rem;
15 | font-family: Arial, sans-serif;
16 | `;
17 |
18 | const Layout = styled.div`
19 | display: flex;
20 | gap: 2rem;
21 | `;
22 |
23 | const FacetContainer = styled.div`
24 | width: 250px;
25 | `;
26 |
27 | const ResultsContainer = styled.div`
28 | flex: 1;
29 | `;
30 |
31 | const ResultItem = styled.div`
32 | display: flex;
33 | align-items: flex-start;
34 | padding: 1rem 0;
35 | border-bottom: 1px solid #ddd;
36 | `;
37 |
38 | const Logo = styled.img`
39 | width: 50px;
40 | height: 50px;
41 | object-fit: contain;
42 | margin-right: 1rem;
43 | `;
44 |
45 | const Info = styled.div`
46 | flex: 1;
47 | `;
48 |
49 | const CompanyName = styled.h3`
50 | margin: 0;
51 | font-size: 1.25rem;
52 | `;
53 |
54 | const OneLiner = styled.p`
55 | margin: 0.5rem 0;
56 | display: -webkit-box;
57 | -webkit-line-clamp: 2;
58 | -webkit-box-orient: vertical;
59 | overflow: hidden;
60 | `;
61 |
62 | const Meta = styled.div`
63 | display: flex;
64 | gap: 1rem;
65 | font-size: 0.9rem;
66 | color: #555;
67 | `;
68 |
69 | const Tags = styled.div`
70 | margin: 0.5rem 0;
71 | `;
72 |
73 | const Tag = styled.span`
74 | background-color: #f0f0f0;
75 | border-radius: 4px;
76 | padding: 0.25rem 0.5rem;
77 | margin-right: 0.5rem;
78 | `;
79 |
80 | const Link = styled.a`
81 | color: #007bff;
82 | text-decoration: none;
83 | &:hover {
84 | text-decoration: underline;
85 | }
86 | `;
87 |
88 | const KNNSearchDefault = (props) => {
89 | const { candidates, vectorDataField } = props;
90 | return (
91 |
97 |
98 | K-Nearest Neighbors Search with Facets
99 |
108 |
109 |
110 |
121 |
122 |
123 | (
144 | <>
145 | {data.map((item) => {
146 | const company = item._source || item;
147 | return (
148 |
149 |
153 |
154 | {company.name}
155 |
156 | {company.one_liner || company.long_description}
157 |
158 |
159 |
160 | {company.team_size}
161 |
162 |
163 | {company.stage}
164 |
165 |
166 |
167 | {company.industries &&
168 | company.industries.map((ind) => (
169 | {ind}
170 | ))}
171 |
172 |
177 | Visit website
178 |
179 |
180 |
181 | );
182 | })}
183 | >
184 | )}
185 | renderNoResults={() => No results found
}
186 | />
187 |
188 |
189 |
190 |
191 | );
192 | };
193 |
194 | export default KNNSearchDefault;
195 |
--------------------------------------------------------------------------------
/stories/reactivesearch/SearchBoxWithCustomAIRender.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { ReactiveBase, SearchBox, SelectedFilters, ReactiveList } from "@appbaseio/reactivesearch";
3 | import { Remarkable } from 'remarkable';
4 | import { booksList as BooksList } from "./resultViews";
5 |
6 |
7 | const md = new Remarkable();
8 |
9 | md.set({
10 | html: true,
11 | breaks: true,
12 | xhtmlOut: true,
13 | linkify: true,
14 | linkTarget: '_blank',
15 | });
16 |
17 | const globalStyles = `
18 | html,
19 | body,
20 | div,
21 | span,
22 | applet,
23 | object,
24 | iframe,
25 | h1,
26 | h2,
27 | h3,
28 | h4,
29 | h5,
30 | h6,
31 | p,
32 | blockquote,
33 | pre,
34 | a,
35 | abbr,
36 | acronym,
37 | address,
38 | big,
39 | cite,
40 | code,
41 | del,
42 | dfn,
43 | em,
44 | img,
45 | ins,
46 | kbd,
47 | q,
48 | s,
49 | samp,
50 | small,
51 | strike,
52 | strong,
53 | sub,
54 | sup,
55 | tt,
56 | var,
57 | b,
58 | u,
59 | i,
60 | center,
61 | dl,
62 | dt,
63 | dd,
64 | ol,
65 | ul,
66 | li,
67 | fieldset,
68 | form,
69 | label,
70 | legend,
71 | table,
72 | caption,
73 | tbody,
74 | tfoot,
75 | thead,
76 | tr,
77 | th,
78 | td,
79 | article,
80 | aside,
81 | canvas,
82 | details,
83 | embed,
84 | figure,
85 | figcaption,
86 | footer,
87 | header,
88 | hgroup,
89 | menu,
90 | nav,
91 | output,
92 | ruby,
93 | section,
94 | summary,
95 | time,
96 | mark,
97 | audio,
98 | video {
99 | margin: 0;
100 | padding: 0;
101 | border: 0;
102 | font-size: 100%;
103 | font: inherit;
104 | vertical-align: baseline;
105 | }
106 |
107 | pre {
108 | margin: 10px auto;
109 | }
110 |
111 | table {
112 | margin: 10px auto;
113 | border-collapse: collapse;
114 | border-spacing: 0;
115 | }
116 |
117 | tr {
118 | border-bottom: 1px solid #ccc;
119 | }
120 |
121 | th,
122 | td {
123 | text-align: left;
124 | padding: 4px;
125 | border: 1px solid;
126 | border-collapse: collapse;
127 | }
128 |
129 | pre,
130 | code {
131 | padding: 0.6em 0.4em;
132 | /* Insert background color */
133 | }
134 |
135 | pre {
136 | /* Insert text color */
137 | white-space: pre-wrap;
138 | }
139 |
140 | code {
141 | line-height: normal;
142 | /* Insert text color */
143 | border-radius: 3px;
144 | font-size: 85%;
145 | padding: 0.2em 0.4em;
146 | margin-top: 5px;
147 | display: inline-block;
148 | overflow: auto;
149 | width: fit-content;
150 | max-width: 100%;
151 | }
152 |
153 | /* Replace 'props.isSender', 'props.themePreset', and 'props.theme.colors' with actual values */
154 |
155 | code[class*='language-'],
156 | pre[class*='language-'] {
157 | /* Insert text color */
158 | text-shadow: none;
159 | }
160 |
161 | ul,
162 | ol {
163 | padding-left: 1rem;
164 | }
165 |
166 | p {
167 | margin: 8px auto;
168 | }
169 | `;
170 |
171 | export const GlobalStyles = () => (
172 |
173 | );
174 |
175 | export default class SearchBoxWithCustomAIRender extends Component {
176 | render() {
177 | return (<>
178 |
187 |
188 |
189 |
{
201 | // custom render AI screen
202 | return (
203 |
204 |
205 | {/* User message */}
206 |
207 | {question &&
216 | {question}
217 |
}
218 |
219 |
220 | {/* AI message */}
221 | {loading ? (
222 |
Loading...
223 | ) : (
224 |
241 | )}
242 |
243 | {/* Sources */}
244 | {!loading && sources && sources.length ? (
245 |
246 | Sources:
247 | {sources.filter(_ => source['original_title']).map((source, index) => (
248 |
249 | {index + 1}. {source['original_title']}
250 |
251 | ))}
252 |
253 | ) : null}
254 |
255 |
256 | );
257 | }
258 | }
259 | />
260 |
261 |
262 |
263 |
274 | {({ data }) => (
275 |
276 | {
277 | data.map(item => )
278 | }
279 |
280 | )}
281 |
282 |
283 |
284 | >
285 | );
286 | }
287 | }
288 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------