Product Catalog (React)

This example uses a common control slicer to filter in DataViews.

This example uses React.

Description
index.html
app.js
data.js
filter.js
locale.js
styles.css

This example uses a common control slicer to filter in DataViews. This demo implements an Amazon-like filter panel with the Card Layout Engine to present a product catalog.

The slicer allows the user to filter the data in the grid using multiple options. This demo filters TVs by size, resolution, and customer reviews.

Try using the filters in the filter panel to pick the type of items that are shown in the grid.

This example uses a common control slicer to filter in DataViews. This demo implements an Amazon-like filter panel with the Card Layout Engine to present a product catalog. The slicer allows the user to filter the data in the grid using multiple options. This demo filters TVs by size, resolution, and customer reviews. Try using the filters in the filter panel to pick the type of items that are shown in the grid.
<!DOCTYPE html> <html lang="en"> <head> <base href="/dataviewsjs/demos/en/sample/Showcase/ProductCatalog/react/" /> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="keywords" content="filtering" /> <meta name="description" content="This example uses a common control slicer to filter in DataViews." /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Product Catalog | Showcase | MESCIUS DataViewsJS React Demos</title> <link href="/dataviewsjs/demos/node_modules/normalize.css/normalize.css" rel="stylesheet" type="text/css" /> <link href="/dataviewsjs/demos/static/css/base.css" rel="stylesheet" type="text/css" /> <link href="/dataviewsjs/demos/static/css/bootstrap-snippet.min.css" rel="stylesheet" type="text/css" /> <link href="/dataviewsjs/demos/node_modules/@fortawesome/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css" /> <link href="/dataviewsjs/demos/static/dataviews/gc.dataviews.core.min.css" rel="stylesheet" type="text/css" /> <link href="/dataviewsjs/demos/static/dataviews/gc.dataviews.cardlayout.min.css" rel="stylesheet" type="text/css" /> <link href="styles.css" rel="stylesheet" type="text/css" /> <script src="/dataviewsjs/demos/static/js/app-polyfills.min.js" type="text/javascript"></script> <script type="text/javascript"> window.process = { env: { NODE_ENV: 'production', USE_NPM: false, USE_CDN: false, SITE_ROOT: '/dataviewsjs/demos', FRAMEWORK: 'react', DVJS_LICENSE_KEY: 'E348418822993781#B0EWvwY4dNNVQqJHUDpFROVWe5ZWNYFlVQFmRsJWRht4Z6lDO4Vla7YUaXhEWxd7Z5YXMuRnY7tWTQRHSlVnaYlXNhlEOpdkZ0FHWYJ5QKd6VXN5aR3ieGhUav9kZTBXWahkYBhEVutmZ72CbjdlZvV5TVdGdiplQsZXe95kUmNmZVF5cJ3mcypWNyx4UydESE3UblxGZyE7KQ94R4BjbUxUewsiaoREMxRDNllWREV6Voh4Q4dDZPRjWrIzUJl4TERXcQZWMHp4Sp9WaMZzN5o6StJmVDJXcwIVVmR6UMVGOlxUW8RmTxZDZTJWVN5GZqJHZuVDMkVGSW3WdxNzKCdDdSB7TzY7cqlnMU5GVyNzNP9WMyhDRvEEOFdkQORDM4dFVlFFWqFWSyMjNQJiOiMlIsISQyIkQ9YjQxIiOigkIsUTM7YjNxYTM0IicfJye&amp;Qf35VfikFVVljI0IyQiwiIxYHITp4c7VWaWFGdhRkI0IiTis7W0ICZyBlIsIiNxUTN6ADI8EDMxMjMwIjI0ICdyNkIsIyc59yc5l6YzVWbuoCLwpmLzVXajNXZt9iKs2WauMXdpN6cl5mLqwSbvNmLzVXajNXZt9iKsAnau26YuMXdpN6cl5mLqwSbvNmL6VGZ9RXajVGchJ7ZuoCLuNmLt36YukHdpNWZwFmcn9iKs46bj9Se4l6YlBXYydmLqwicr9ybj9Se4l6YlBXYydmLqwCcq9ybj9Se4l6YlBXYydmLqIiOiMXbEJCLiMVVJN4UF5kI0ISYONkIsUWdyRnOiwmdFJCLiEDO7MTO9IjM8gTM4gDNzIiOiQWSisnOiQkIsISP3EkVxBVUHFDMplzLlVUdGd7cI9UeIt4SshESzV7NvY7ZxlDOuNTb5tzLr', SJS_LICENSE_KEY: 'E518585142165236#B0wm4nx4QzdlTHRTSOFzcvVnaJdjSnNEeXdTMUtSUzk6bU94QuVXNwZVZjd4SzYjcadXRIVEMzEXTThkVyR7R85UayoHZZBTYQ5mZyh4Shd6VxFXazF4cBNGRG5WTvUGTsV4T6knQYRzKxxUdk9EarplU7d6VLF6KIR7bPJ5N6ZUMWZWaURGRKRDbLJDN5YjSN5mUoxmaxonSD56LEh7Y7RXenpmTvomevZlV9dkaysCO7hTRQFHcGRWQyc5LI9kQmB7QwR4Z7ZHOR3CSXp6SiFWYzFXeXZUSp94K8VDTkFjdwl4KptSYlRWcDxmNE5kS6kzdrkVcNJXROVGbLJkcTNGRzIER8tmd4YGNhh7dxAnMvIHRv46VtBXS4U5KvJ6dZJ6M5p4TxIjd9I5QSpXTTV6SDZXb7lzaL56ZiojITJCLikTQxUTQFV4NiojIIJCLyETO7UzM7kTO0IicfJye&amp;Qf35VfikkR9IkI0IyQiwiIyEjL6ByUKBCZhVmcwNlI0IiTis7W0ICZyBlIsISNwkTN6ADI8EDMxMjMwIjI0ICdyNkIsIyc59yc5l6YzVWbuoCLwpmLzVXajNXZt9iKs2WauMXdpN6cl5mLqwSbvNmLzVXajNXZt9iKsAnau26YuMXdpN6cl5mLqwSbvNmL6VGZ9RXajVGchJ7ZuoCLuNmLt36YukHdpNWZwFmcn9iKs46bj9Se4l6YlBXYydmLqwicr9ybj9Se4l6YlBXYydmLqwCcq9ybj9Se4l6YlBXYydmLqIiOiMXbEJCLiMVVJN4UF5kI0ISYONkIsUWdyRnOiwmdFJCLiYzMyUjNxIDNxUDO5gTM5IiOiQWSiwSfdtlOicGbmJCLlNHbhZmOiI7ckJye0ICbuFkI1pjIEJCLi4TPRtGOhtWWEFWd4IDOLRVRvx4SyMGcDhTW6n4ep', }, }; </script> <script src="/dataviewsjs/demos/node_modules/lodash/lodash.min.js" type="text/javascript"></script> <script src="//cdn.mescius.com/spreadjs/hosted/scripts/gc.spread.common.12.0.0.min.js" type="text/javascript" ></script> <script src="/dataviewsjs/demos/node_modules/jquery/dist/jquery.min.js" type="text/javascript"></script> <script src="/dataviewsjs/demos/static/js/license.js" type="text/javascript"></script> <script src="/dataviewsjs/demos/node_modules/systemjs/dist/system.js" type="text/javascript"></script> <script src="systemjs.config.js" type="text/javascript"></script> </head> <body class="theme-default"> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> <script type="text/javascript"> System.import('./app.js'); </script> </body> </html>
import _ from 'lodash'; import React from 'react'; import ReactDOM from 'react-dom'; import DataView, { getControlByElement } from '@grapecity/dataviews.react'; import CardLayout from '@grapecity/dataviews.cardlayout'; import Filter from './filter'; import { data } from './data'; import locale from './locale'; const rowTemplate = `<div> <div data-column="image"></div> <div data-column="description"></div> <div data-column="brand"></div> <div data-column="price"></div> <div data-column="starsIcon"></div> </div>`; const imagePresenter = '<img class="tv-image" src={{=it.image}} />'; const descriptionPresenter = '<a><b>{{=it.description}}</b></a>'; const brandPresenter = '<div class="tv-brand"><label>by {{=it.brand}}</label></div>'; const pricePresenter = '<div>${{=it.price}}</div>'; const startPresenter = '<div class="stars-box {{=it.starsIcon}}"></div>'; const cols = [ { id: 'image', caption: 'Image', dataField: 'image', presenter: imagePresenter, }, { id: 'description', caption: 'Description', dataField: 'description', presenter: descriptionPresenter, }, { id: 'brand', caption: 'Brand', dataField: 'brand', presenter: brandPresenter, }, { id: 'price', caption: 'Price', dataField: 'price', presenter: pricePresenter, }, { id: 'starsIcon', caption: 'StarsIcon', dataField: 'starsIcon', presenter: startPresenter, }, { id: 'size', caption: 'TV Display Size', dataField: 'size' }, { id: 'refreshRate', caption: 'RefreshRate', dataField: 'refreshRate' }, { id: 'resolution', caption: 'Television Resolution', dataField: 'resolution', }, { id: 'starsValue', caption: 'Avg. Customer Review', dataField: 'starsValue', }, ]; const getCaption = (id) => _.find(cols, (col) => col.id === id).caption; const dataNames = _.keys(data[0]); const dataValues = _.map(data, (item) => _.values(item)); const dataSource = new GC.Spread.Slicers.GeneralSlicerData(dataValues, dataNames); const layout = new CardLayout({ cardHeight: 300, cardWidth: 210, rowTemplate, }); dataSource.attachListener({ onFiltered(args) { const newData = _.map(args.rowIndexes, (index) => data[index]); const dataView = getControlByElement(document.body); dataView.data.setSource_(newData); // Need to be replaced dataView.invalidate(); }, }); const sizeRanges = [ { range: { min: -Infinity, max: 32 }, label: '32 Inches & Under' }, { range: { min: 33, max: 43 }, label: '33 to 43 Inches' }, { range: { min: 44, max: 49 }, label: '44 to 49 Inches' }, { range: { min: 50, max: 59 }, label: '50 to 59 Inches' }, { range: { min: 60, max: 69 }, label: '60 to 69 Inches' }, { range: { min: 70, max: Infinity }, label: '70 Inches & Up' }, ]; const reviewRanges = _.rangeRight(1, 5).map((min) => ({ range: { min, max: Infinity }, label: ( <span> <span className={`stars-box stars-${min}`} /> <span className="label">&amp;Up</span> </span> ), })); const App = () => { const toggleFilterPanel = () => { $('.filter-panel').toggle(); }; return ( <div className="demo-container"> <div className="mobile-filter-entry"> <div className="filter-condition" onClick={toggleFilterPanel}> <span className="filter-label">{locale.filter}</span> <span className="fa fa-angle-down" /> </div> </div> <div className="filter-panel"> <div className="filter-header">{locale.refineBy}</div> <Filter dataSource={dataSource} caption={getCaption('size')} columnName="size" ranges={sizeRanges} /> <Filter dataSource={dataSource} caption={getCaption('resolution')} columnName="resolution" /> <Filter dataSource={dataSource} caption={getCaption('starsValue')} columnName="starsValue" ranges={reviewRanges} /> </div> <DataView id="grid" class="grid" data={data} cols={cols} layout={layout} /> </div> ); }; ReactDOM.render(<App />, document.getElementById('root')); window.addEventListener('resize', () => { const isMobile = $('.mobile-filter-entry').is(':visible'); $('.filter-panel').toggle(!isMobile); });
const SITE_ROOT = window.process.env.SITE_ROOT; export const data = [ { size: 42, refreshRate: 60, resolution: '1080p', price: 399.49, brand: 'LG', starsIcon: 'stars-4-5', starsValue: 4.5, image: SITE_ROOT + '/images/51RgQIPeyfL._AA160_.jpg', shipToChina: true, description: 'LG Electronics 42LF5600 42-Inch 1080p 60Hz LED TV', }, { size: 105, refreshRate: 120, resolution: '4K', price: 119999.99, brand: 'Samsung', starsIcon: 'stars-4', starsValue: 4, image: SITE_ROOT + '/images/411r27g4Y4L._AA160_.jpg', shipToChina: true, description: 'Samsung UN105S9 Curved 105-Inch 4K Ultra HD 120Hz 3D Smart LED TV', }, { size: 32, refreshRate: 60, resolution: '720p', price: 237.99, brand: 'Samsung', starsIcon: 'stars-5', starsValue: 5, image: SITE_ROOT + '/images/510PicygL._AA160_.jpg', shipToChina: false, description: 'Samsung UN32J4000 32-Inch 720p LED TV', }, { size: 22, refreshRate: 60, resolution: '1080p', price: 167.99, brand: 'Samsung', starsIcon: 'stars-4-5', starsValue: 4.5, image: SITE_ROOT + '/images/41yd3HTcniL._AA160_.jpg', shipToChina: false, description: 'Samsung UN22F5000 22-Inch 1080p 60Hz LED HDTV (2013 Model)', }, { size: 42, refreshRate: 60, resolution: '1080p', price: 499.99, brand: 'LG', starsIcon: 'stars-3', starsValue: 3, image: SITE_ROOT + '/images/517B8PMhPNL._AA160_.jpg', shipToChina: false, description: 'LG 42LB5600 42-Inch TV (2014 Model)', }, { size: 45, refreshRate: 60, resolution: '1080p', price: 259.99, brand: 'Samsung', starsIcon: 'stars-4', starsValue: 4, image: SITE_ROOT + '/images/516z8QST2CL._AA160_.jpg', shipToChina: true, description: 'Samsung UN32H5203 45-Inch 1080p 60Hz Smart LED TV', }, { size: 46, refreshRate: 60, resolution: '1080p', price: 497.99, brand: 'Samsung', starsIcon: 'stars-3', starsValue: 3, image: SITE_ROOT + '/images/41H0LXbYcXL._AA160_.jpg', shipToChina: true, description: 'Samsung UN32J6300 46-Inch 1080p Smart LED TV', }, { size: 32, refreshRate: 60, resolution: '720p', price: 179.99, brand: 'Upstar', starsIcon: 'stars-4-5', starsValue: 4.5, image: SITE_ROOT + '/images/41JXS3PTiJL._AA160_.jpg', shipToChina: false, description: 'Upstar P32ES8 32-Inch 720p 60Hz LED TV', }, { size: 40, refreshRate: 60, resolution: '480p', price: 327.99, brand: 'Samsung', starsIcon: 'stars-4-5', starsValue: 4.5, image: SITE_ROOT + '/images/51JegzA81lL._AA160_.jpg', shipToChina: false, description: 'Samsung UN40H5003 40-Inch 480p 60Hz LED TV', }, { size: 55, refreshRate: 120, resolution: '1080p', price: 727.25, brand: 'LG', starsIcon: 'stars-4-5', starsValue: 4.5, image: SITE_ROOT + '/images/51yUo1AhEdL._AA160_.jpg', shipToChina: false, description: 'LG Electronics 55LB5900 55-Inch 1080p 120Hz LED TV (2014 Model)', }, { size: 55, refreshRate: 120, resolution: '1080p', price: 679.99, brand: 'LG', starsIcon: 'stars-4', starsValue: 4, image: SITE_ROOT + '/images/4112L6fBNLL._AA160_.jpg', shipToChina: false, description: 'LG Electronics 55LF6000 55-Inch 1080p 120Hz LED TV', }, { size: 24, refreshRate: 60, resolution: '1080p', price: 178.99, brand: 'VIZIO', starsIcon: 'stars-4', starsValue: 4, image: SITE_ROOT + '/images/51tJrIAnF0L._AA160_.jpg', shipToChina: true, description: 'VIZIO E241i-B1 24-Inch 1080p 60Hz Smart LED HDTV (Black)', }, { size: 40, refreshRate: 60, resolution: '1080p', price: 353.7, brand: 'TCL', starsIcon: 'stars-5', starsValue: 5, image: SITE_ROOT + '/images/41iZ3NkxiL._AA160_.jpg', shipToChina: true, description: 'TCL 40FS4610R 40-Inch 1080p Smart LED TV (Roku TV)', }, { size: 55, refreshRate: 60, resolution: '1080p', price: 1000.42, brand: 'Samsung', starsIcon: 'stars-3', starsValue: 3, image: SITE_ROOT + '/images/41H0LXbYcXL._AA160_.jpg', shipToChina: false, description: 'Samsung UN55J6300 55-Inch 1080p Smart LED TV', }, { size: 39, refreshRate: 60, resolution: '1080p', price: 279.99, brand: 'VIZIO', starsIcon: 'stars-5', starsValue: 5, image: SITE_ROOT + '/images/41Voh4kl2hL._AA160_.jpg', shipToChina: false, description: 'VIZIO E390-A1 39-Inch 1080p 60Hz LED TV (Refurbished)', }, { size: 60, refreshRate: 120, resolution: '1080p', price: 899.99, brand: 'LG', starsIcon: 'stars-4', starsValue: 4, image: SITE_ROOT + '/images/51Gx1C4mEFL._AA160_.jpg', shipToChina: false, description: 'LG Electronics 60LB5900 60-Inch 1080p 120Hz LED TV (2014 Model)', }, { size: 32, refreshRate: 60, resolution: '1080p', price: 299.99, brand: 'LG', starsIcon: 'stars-4-5', starsValue: 4.5, image: SITE_ROOT + '/images/51RgQIPeyfL._AA160_.jpg', shipToChina: false, description: 'LG Electronics 32LF5600 32-Inch 1080p 60Hz LED TV', }, { size: 40, refreshRate: 60, resolution: '1080p', price: 307.99, brand: 'TCL', starsIcon: 'stars-4-5', starsValue: 4.5, image: SITE_ROOT + '/images/416bLnX49L._AA160_.jpg', shipToChina: false, description: 'TCL LE40FHDE3010 40-Inch 1080p 60Hz LED TV', }, { size: 28, refreshRate: 60, resolution: '720p', price: 165.99, brand: 'Samsung', starsIcon: 'stars-4-5', starsValue: 4.5, image: SITE_ROOT + '/images/51y45mtIPgL._AA160_.jpg', shipToChina: false, description: 'Samsung UN28H4000 28-Inch 720p 60Hz LED TV', }, { size: 43, refreshRate: 60, resolution: '1080p', price: 445.49, brand: 'VIZIO', starsIcon: 'stars-4-5', starsValue: 4.5, image: SITE_ROOT + '/images/51OEEpDqNHL._AA160_.jpg', shipToChina: false, description: 'VIZIO E43-C2 43-Inch 1080p Smart LED HDTV', }, ]; const dataNames = _.keys(data[0]); const dataValues = _.map(data, (item) => _.values(item)); export const dataSource = new GC.Spread.Slicers.GeneralSlicerData(dataValues, dataNames); export function getItemStates(dataSource, rangeState, columnName) { const byOtherColumns = GC.Spread.Slicers.FilteredOutDataType.byOtherColumns; const filteredIndexes = dataSource.getFilteredIndexes(columnName); const filteredOutIndexes = dataSource.getFilteredOutIndexes(columnName, byOtherColumns); const filtered = new Set(); const filteredOut = new Set(); if (rangeState) { const exclusiveData = dataSource.getExclusiveData(columnName); const filteredValues = filteredIndexes.map((i) => exclusiveData[i]); const filteredOutValues = filteredOutIndexes.map((i) => exclusiveData[i]); for (let k = 0; k < rangeState.length; k++) { const range = rangeState[k].range; const inrange = (val) => val >= range.min && val <= range.max; if (filteredValues.some(inrange)) { filtered.add(k); } if (filteredOutValues.some(inrange)) { filteredOut.add(k); } } } else { filteredIndexes.forEach((k) => { filtered.add(k); }); filteredOutIndexes.forEach((k) => { filteredOut.add(k); }); } return { filtered, filteredOut }; }
import _ from 'lodash'; import React from 'react'; import { getItemStates } from './data'; const { useState, useEffect } = React; function classNames(...args) { const t = args.filter(_.identity).map((a) => (_.isString(a) ? a : Object.keys(a).filter((k) => !!a[k]))); return _.flatten(t).join(' '); } const useForceUpdate = () => { const [it, setIt] = useState(false); return () => setIt(!it); }; function useSlicerData(dataSource) { const forceUpdate = useForceUpdate(); const listener = { onFiltered() { forceUpdate(); }, }; useEffect(() => { dataSource.attachListener(listener); return () => { dataSource.detachListener(listener); }; }); return forceUpdate; } function filterByRanges(dataSource, columnName, ranges) { if (_.isEmpty(ranges)) { dataSource.doUnfilter(columnName); } else { dataSource.doFilter(columnName, { ranges }); } } function filterByIndexes(dataSource, columnName, checked) { const indexes = checked .map((v, i) => [i, v]) .filter(([, v]) => !!v) .map(([i]) => i); if (_.isEmpty(indexes)) { dataSource.doUnfilter(columnName); } else { dataSource.doFilter(columnName, { exclusiveRowIndexes: indexes }); } } const Item = ({ className, label, count, disabled, checked, onChange }) => { const handleChange = (checked) => { if (!disabled) { onChange(checked); } }; return ( <div className={classNames('slicer-item', className)} onClick={() => handleChange(!checked)}> <input type="checkbox" disabled={!!disabled} checked={!!checked} onChange={(e) => handleChange(e.target.checked)} /> <span>{label}</span> <span className="count-badge">({count})</span> </div> ); }; const Filter = ({ dataSource, caption, columnName, ranges }) => { const isRangeFilter = !!ranges; const data = ranges || dataSource.getExclusiveData(columnName); const [checked, setChecked] = useState(data.map((t) => false)); useSlicerData(dataSource); const { filtered, filteredOut } = getItemStates(dataSource, ranges, columnName); const items = data.map((it, idx) => { const handleChange = (value) => { checked[idx] = value; setChecked(checked.slice()); if (isRangeFilter) { const selectedRanges = ranges.filter((t, i) => checked[i]).map((t) => t.range); filterByRanges(dataSource, columnName, selectedRanges); } else { filterByIndexes(dataSource, columnName, checked); } }; const count = isRangeFilter ? dataSource.getData(columnName, it.range).length : dataSource.getRowIndexes(columnName, idx).length; const className = classNames({ filtered: filtered.has(idx), filteredOutByOther: filteredOut.has(idx), }); return ( <Item key={idx} className={className} label={isRangeFilter ? it.label : it} count={count} disabled={filteredOut.has(idx)} checked={checked[idx]} onChange={handleChange} /> ); }); return ( <div> <div className="filter-details">{caption}</div> {items} </div> ); }; export default Filter;
module.exports = { filter: 'Filter', refineBy: 'Refine by' };
label { font-weight: normal; margin: 0; } .card-layout.gc-grid { border: 0; } .card-layout .gc-row { padding: 3px; text-align: center; } .card-layout .gc-row .gc-cell { justify-content: center; } #grid { height: 100%; left: 220px; position: absolute; right: 0; } .demo-container { height: 100%; position: relative; -webkit-user-select: none; -ms-user-select: none; user-select: none; width: 100%; } .filter-panel { border: 0; display: block; float: left; height: 100%; overflow: auto; padding-left: 8px; position: static; width: 219px; z-index: auto; } .filter-header { color: #999; font-size: 17px; padding-bottom: 10px; padding-top: 6px; } .filter-details { font-size: 14px; font-weight: 700; padding-bottom: 3px; } .stars-box { background-image: url("/dataviewsjs/demos/images/star-ratings.png"); display: inline-block; height: 13px; overflow: hidden; vertical-align: middle; width: 65px; margin-right: 4px; } .stars-0 { background-position: -65px 0; } .stars-0-5 { background-position: -52px -19px; } .stars-1 { background-position: -52px 0; } .stars-1-5 { background-position: -39px -19px; } .stars-2 { background-position: -39px 0; } .stars-2-5 { background-position: -26px -19px; } .stars-3 { background-position: -26px 0; } .stars-3-5 { background-position: -13px -19px; } .stars-4 { background-position: -13px 0; } .stars-4-5 { background-position: 0 -18px; } .stars-5 { background-position: 0 0; } .tv-image { margin-left: 10px; } .tv-brand { color: #d3d3d3; font-size: 13px; } .tv-price { color: #b12704; } .mobile-filter-entry { display: none; } .filter-condition { border: 1px solid #d3d3d3; cursor: pointer; display: inline-block; font-size: 16px; height: 25px; text-align: center; width: 100px; } .filter-condition .filter-label { margin-right: 5px; } .slicer { margin: 10px 0; } .slicer-item { align-items: center; cursor: pointer; display: flex; margin: 2px 0; } .slicer-item.selected { color: #337ab7; } .slicer-item.selected .label { font-weight: bold; } .slicer-item:hover { color: #e47911; } .slicer-item.filtered { background-color: #fff; } .slicer-item.filteredOutByOther { color: #a6a8b1; } .slicer-item.filteredOutBySelf { background-color: #fff; } .slicer-item input { margin-right: 4px; } .slicer-item .count-badge { margin-left: 4px; color: #a29999; } @media only screen and (max-width: 768px) { #grid { height: 90%; position: static; } .filter-panel { background: #fff; border: 1px solid #d3d3d3; display: none; height: calc(100% - 25px); margin-top: -1px; overflow: auto; padding: 5px 0 0 10px; position: absolute; width: 100%; z-index: 1; } .mobile-filter-entry { display: block; height: 25px; } } /*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIlNob3djYXNlL1Byb2R1Y3RDYXRhbG9nL3JlYWN0L3N0eWxlcy5zY3NzIiwiU2hvd2Nhc2UvUHJvZHVjdENhdGFsb2cvcmVhY3Qvc3R5bGVzLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLG1CQUFBO0VBQ0EsU0FBQTtBQ0NGOztBREVBO0VBQ0UsU0FBQTtBQ0NGOztBREVBO0VBQ0UsWUFBQTtFQUNBLGtCQUFBO0FDQ0Y7QURDRTtFQUNFLHVCQUFBO0FDQ0o7O0FER0E7RUFDRSxZQUFBO0VBQ0EsV0FBQTtFQUNBLGtCQUFBO0VBQ0EsUUFBQTtBQ0FGOztBREdBO0VBQ0UsWUFBQTtFQUNBLGtCQUFBO0VBQ0EseUJBQUE7TUFBQSxxQkFBQTtVQUFBLGlCQUFBO0VBQ0EsV0FBQTtBQ0FGOztBREdBO0VBQ0UsU0FBQTtFQUNBLGNBQUE7RUFDQSxXQUFBO0VBQ0EsWUFBQTtFQUNBLGNBQUE7RUFDQSxpQkFBQTtFQUNBLGdCQUFBO0VBQ0EsWUFBQTtFQUNBLGFBQUE7QUNBRjs7QURHQTtFQUNFLFdBQUE7RUFDQSxlQUFBO0VBQ0Esb0JBQUE7RUFDQSxnQkFBQTtBQ0FGOztBREdBO0VBQ0UsZUFBQTtFQUNBLGdCQUFBO0VBQ0EsbUJBQUE7QUNBRjs7QURHQTtFQUNFLG1FQUFBO0VBQ0EscUJBQUE7RUFDQSxZQUFBO0VBQ0EsZ0JBQUE7RUFDQSxzQkFBQTtFQUNBLFdBQUE7RUFDQSxpQkFBQTtBQ0FGOztBREdBO0VBQ0UsNEJBQUE7QUNBRjs7QURHQTtFQUNFLGdDQUFBO0FDQUY7O0FER0E7RUFDRSw0QkFBQTtBQ0FGOztBREdBO0VBQ0UsZ0NBQUE7QUNBRjs7QURHQTtFQUNFLDRCQUFBO0FDQUY7O0FER0E7RUFDRSxnQ0FBQTtBQ0FGOztBREdBO0VBQ0UsNEJBQUE7QUNBRjs7QURHQTtFQUNFLGdDQUFBO0FDQUY7O0FER0E7RUFDRSw0QkFBQTtBQ0FGOztBREdBO0VBQ0UsNEJBQUE7QUNBRjs7QURHQTtFQUNFLHdCQUFBO0FDQUY7O0FER0E7RUFDRSxpQkFBQTtBQ0FGOztBREdBO0VBQ0UsY0FBQTtFQUNBLGVBQUE7QUNBRjs7QURHQTtFQUNFLGNBQUE7QUNBRjs7QURHQTtFQUNFLGFBQUE7QUNBRjs7QURHQTtFQUNFLHlCQUFBO0VBQ0EsZUFBQTtFQUNBLHFCQUFBO0VBQ0EsZUFBQTtFQUNBLFlBQUE7RUFDQSxrQkFBQTtFQUNBLFlBQUE7QUNBRjtBREVFO0VBQ0UsaUJBQUE7QUNBSjs7QURJQTtFQUNFLGNBQUE7QUNERjs7QURJQTtFQUNFLG1CQUFBO0VBQ0EsZUFBQTtFQUdBLGFBQUE7RUFDQSxhQUFBO0FDREY7QURHRTtFQUNFLGNBQUE7QUNESjtBREdJO0VBQ0UsaUJBQUE7QUNETjtBREtFO0VBQ0UsY0FBQTtBQ0hKO0FETUU7RUFDRSxzQkFBQTtBQ0pKO0FET0U7RUFDRSxjQUFBO0FDTEo7QURRRTtFQUNFLHNCQUFBO0FDTko7QURTRTtFQUNFLGlCQUFBO0FDUEo7QURVRTtFQUNFLGdCQUFBO0VBQ0EsY0FBQTtBQ1JKOztBRFlBO0VBQ0U7SUFDRSxXQUFBO0lBQ0EsZ0JBQUE7RUNURjs7RURZQTtJQUNFLGdCQUFBO0lBQ0EseUJBQUE7SUFDQSxhQUFBO0lBQ0EseUJBQUE7SUFDQSxnQkFBQTtJQUNBLGNBQUE7SUFDQSxxQkFBQTtJQUNBLGtCQUFBO0lBQ0EsV0FBQTtJQUNBLFVBQUE7RUNURjs7RURZQTtJQUNFLGNBQUE7SUFDQSxZQUFBO0VDVEY7QUFDRiIsImZpbGUiOiJTaG93Y2FzZS9Qcm9kdWN0Q2F0YWxvZy9yZWFjdC9zdHlsZXMuY3NzIiwic291cmNlc0NvbnRlbnQiOlsibGFiZWwge1xuICBmb250LXdlaWdodDogbm9ybWFsO1xuICBtYXJnaW46IDA7XG59XG5cbi5jYXJkLWxheW91dC5nYy1ncmlkIHtcbiAgYm9yZGVyOiAwO1xufVxuXG4uY2FyZC1sYXlvdXQgLmdjLXJvdyB7XG4gIHBhZGRpbmc6IDNweDtcbiAgdGV4dC1hbGlnbjogY2VudGVyO1xuXG4gIC5nYy1jZWxsIHtcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgfVxufVxuXG4jZ3JpZCB7XG4gIGhlaWdodDogMTAwJTtcbiAgbGVmdDogMjIwcHg7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgcmlnaHQ6IDA7XG59XG5cbi5kZW1vLWNvbnRhaW5lciB7XG4gIGhlaWdodDogMTAwJTtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICB1c2VyLXNlbGVjdDogbm9uZTtcbiAgd2lkdGg6IDEwMCU7XG59XG5cbi5maWx0ZXItcGFuZWwge1xuICBib3JkZXI6IDA7XG4gIGRpc3BsYXk6IGJsb2NrO1xuICBmbG9hdDogbGVmdDtcbiAgaGVpZ2h0OiAxMDAlO1xuICBvdmVyZmxvdzogYXV0bztcbiAgcGFkZGluZy1sZWZ0OiA4cHg7XG4gIHBvc2l0aW9uOiBzdGF0aWM7XG4gIHdpZHRoOiAyMTlweDtcbiAgei1pbmRleDogYXV0bztcbn1cblxuLmZpbHRlci1oZWFkZXIge1xuICBjb2xvcjogIzk5OTtcbiAgZm9udC1zaXplOiAxN3B4O1xuICBwYWRkaW5nLWJvdHRvbTogMTBweDtcbiAgcGFkZGluZy10b3A6IDZweDtcbn1cblxuLmZpbHRlci1kZXRhaWxzIHtcbiAgZm9udC1zaXplOiAxNHB4O1xuICBmb250LXdlaWdodDogNzAwO1xuICBwYWRkaW5nLWJvdHRvbTogM3B4O1xufVxuXG4uc3RhcnMtYm94IHtcbiAgYmFja2dyb3VuZC1pbWFnZTogdXJsKCcvZGF0YXZpZXdzanMvZGVtb3MvaW1hZ2VzL3N0YXItcmF0aW5ncy5wbmcnKTtcbiAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICBoZWlnaHQ6IDEzcHg7XG4gIG92ZXJmbG93OiBoaWRkZW47XG4gIHZlcnRpY2FsLWFsaWduOiBtaWRkbGU7XG4gIHdpZHRoOiA2NXB4O1xuICBtYXJnaW4tcmlnaHQ6IDRweDtcbn1cblxuLnN0YXJzLTAge1xuICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiAtNjVweCAwO1xufVxuXG4uc3RhcnMtMC01IHtcbiAgYmFja2dyb3VuZC1wb3NpdGlvbjogLTUycHggLTE5cHg7XG59XG5cbi5zdGFycy0xIHtcbiAgYmFja2dyb3VuZC1wb3NpdGlvbjogLTUycHggMDtcbn1cblxuLnN0YXJzLTEtNSB7XG4gIGJhY2tncm91bmQtcG9zaXRpb246IC0zOXB4IC0xOXB4O1xufVxuXG4uc3RhcnMtMiB7XG4gIGJhY2tncm91bmQtcG9zaXRpb246IC0zOXB4IDA7XG59XG5cbi5zdGFycy0yLTUge1xuICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiAtMjZweCAtMTlweDtcbn1cblxuLnN0YXJzLTMge1xuICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiAtMjZweCAwO1xufVxuXG4uc3RhcnMtMy01IHtcbiAgYmFja2dyb3VuZC1wb3NpdGlvbjogLTEzcHggLTE5cHg7XG59XG5cbi5zdGFycy00IHtcbiAgYmFja2dyb3VuZC1wb3NpdGlvbjogLTEzcHggMDtcbn1cblxuLnN0YXJzLTQtNSB7XG4gIGJhY2tncm91bmQtcG9zaXRpb246IDAgLTE4cHg7XG59XG5cbi5zdGFycy01IHtcbiAgYmFja2dyb3VuZC1wb3NpdGlvbjogMCAwO1xufVxuXG4udHYtaW1hZ2Uge1xuICBtYXJnaW4tbGVmdDogMTBweDtcbn1cblxuLnR2LWJyYW5kIHtcbiAgY29sb3I6ICNkM2QzZDM7XG4gIGZvbnQtc2l6ZTogMTNweDtcbn1cblxuLnR2LXByaWNlIHtcbiAgY29sb3I6ICNiMTI3MDQ7XG59XG5cbi5tb2JpbGUtZmlsdGVyLWVudHJ5IHtcbiAgZGlzcGxheTogbm9uZTtcbn1cblxuLmZpbHRlci1jb25kaXRpb24ge1xuICBib3JkZXI6IDFweCBzb2xpZCAjZDNkM2QzO1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgZm9udC1zaXplOiAxNnB4O1xuICBoZWlnaHQ6IDI1cHg7XG4gIHRleHQtYWxpZ246IGNlbnRlcjtcbiAgd2lkdGg6IDEwMHB4O1xuXG4gIC5maWx0ZXItbGFiZWwge1xuICAgIG1hcmdpbi1yaWdodDogNXB4O1xuICB9XG59XG5cbi5zbGljZXIge1xuICBtYXJnaW46IDEwcHggMDtcbn1cblxuLnNsaWNlci1pdGVtIHtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBkaXNwbGF5OiAtd2Via2l0LWJveDtcbiAgZGlzcGxheTogLW1zLWZsZXhib3g7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIG1hcmdpbjogMnB4IDA7XG5cbiAgJi5zZWxlY3RlZCB7XG4gICAgY29sb3I6ICMzMzdhYjc7XG5cbiAgICAubGFiZWwge1xuICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7XG4gICAgfVxuICB9XG5cbiAgJjpob3ZlciB7XG4gICAgY29sb3I6ICNlNDc5MTE7XG4gIH1cblxuICAmLmZpbHRlcmVkIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmO1xuICB9XG5cbiAgJi5maWx0ZXJlZE91dEJ5T3RoZXIge1xuICAgIGNvbG9yOiAjYTZhOGIxO1xuICB9XG5cbiAgJi5maWx0ZXJlZE91dEJ5U2VsZiB7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogI2ZmZjtcbiAgfVxuXG4gIGlucHV0IHtcbiAgICBtYXJnaW4tcmlnaHQ6IDRweDtcbiAgfVxuXG4gIC5jb3VudC1iYWRnZSB7XG4gICAgbWFyZ2luLWxlZnQ6IDRweDtcbiAgICBjb2xvcjogI2EyOTk5OTtcbiAgfVxufVxuXG5AbWVkaWEgb25seSBzY3JlZW4gYW5kIChtYXgtd2lkdGg6IDc2OHB4KSB7XG4gICNncmlkIHtcbiAgICBoZWlnaHQ6IDkwJTtcbiAgICBwb3NpdGlvbjogc3RhdGljO1xuICB9XG5cbiAgLmZpbHRlci1wYW5lbCB7XG4gICAgYmFja2dyb3VuZDogI2ZmZjtcbiAgICBib3JkZXI6IDFweCBzb2xpZCAjZDNkM2QzO1xuICAgIGRpc3BsYXk6IG5vbmU7XG4gICAgaGVpZ2h0OiBjYWxjKDEwMCUgLSAyNXB4KTtcbiAgICBtYXJnaW4tdG9wOiAtMXB4O1xuICAgIG92ZXJmbG93OiBhdXRvO1xuICAgIHBhZGRpbmc6IDVweCAwIDAgMTBweDtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgei1pbmRleDogMTtcbiAgfVxuXG4gIC5tb2JpbGUtZmlsdGVyLWVudHJ5IHtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBoZWlnaHQ6IDI1cHg7XG4gIH1cbn1cbiIsImxhYmVsIHtcbiAgZm9udC13ZWlnaHQ6IG5vcm1hbDtcbiAgbWFyZ2luOiAwO1xufVxuXG4uY2FyZC1sYXlvdXQuZ2MtZ3JpZCB7XG4gIGJvcmRlcjogMDtcbn1cblxuLmNhcmQtbGF5b3V0IC5nYy1yb3cge1xuICBwYWRkaW5nOiAzcHg7XG4gIHRleHQtYWxpZ246IGNlbnRlcjtcbn1cbi5jYXJkLWxheW91dCAuZ2Mtcm93IC5nYy1jZWxsIHtcbiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG59XG5cbiNncmlkIHtcbiAgaGVpZ2h0OiAxMDAlO1xuICBsZWZ0OiAyMjBweDtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICByaWdodDogMDtcbn1cblxuLmRlbW8tY29udGFpbmVyIHtcbiAgaGVpZ2h0OiAxMDAlO1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIHVzZXItc2VsZWN0OiBub25lO1xuICB3aWR0aDogMTAwJTtcbn1cblxuLmZpbHRlci1wYW5lbCB7XG4gIGJvcmRlcjogMDtcbiAgZGlzcGxheTogYmxvY2s7XG4gIGZsb2F0OiBsZWZ0O1xuICBoZWlnaHQ6IDEwMCU7XG4gIG92ZXJmbG93OiBhdXRvO1xuICBwYWRkaW5nLWxlZnQ6IDhweDtcbiAgcG9zaXRpb246IHN0YXRpYztcbiAgd2lkdGg6IDIxOXB4O1xuICB6LWluZGV4OiBhdXRvO1xufVxuXG4uZmlsdGVyLWhlYWRlciB7XG4gIGNvbG9yOiAjOTk5O1xuICBmb250LXNpemU6IDE3cHg7XG4gIHBhZGRpbmctYm90dG9tOiAxMHB4O1xuICBwYWRkaW5nLXRvcDogNnB4O1xufVxuXG4uZmlsdGVyLWRldGFpbHMge1xuICBmb250LXNpemU6IDE0cHg7XG4gIGZvbnQtd2VpZ2h0OiA3MDA7XG4gIHBhZGRpbmctYm90dG9tOiAzcHg7XG59XG5cbi5zdGFycy1ib3gge1xuICBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoXCIvZGF0YXZpZXdzanMvZGVtb3MvaW1hZ2VzL3N0YXItcmF0aW5ncy5wbmdcIik7XG4gIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgaGVpZ2h0OiAxM3B4O1xuICBvdmVyZmxvdzogaGlkZGVuO1xuICB2ZXJ0aWNhbC1hbGlnbjogbWlkZGxlO1xuICB3aWR0aDogNjVweDtcbiAgbWFyZ2luLXJpZ2h0OiA0cHg7XG59XG5cbi5zdGFycy0wIHtcbiAgYmFja2dyb3VuZC1wb3NpdGlvbjogLTY1cHggMDtcbn1cblxuLnN0YXJzLTAtNSB7XG4gIGJhY2tncm91bmQtcG9zaXRpb246IC01MnB4IC0xOXB4O1xufVxuXG4uc3RhcnMtMSB7XG4gIGJhY2tncm91bmQtcG9zaXRpb246IC01MnB4IDA7XG59XG5cbi5zdGFycy0xLTUge1xuICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiAtMzlweCAtMTlweDtcbn1cblxuLnN0YXJzLTIge1xuICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiAtMzlweCAwO1xufVxuXG4uc3RhcnMtMi01IHtcbiAgYmFja2dyb3VuZC1wb3NpdGlvbjogLTI2cHggLTE5cHg7XG59XG5cbi5zdGFycy0zIHtcbiAgYmFja2dyb3VuZC1wb3NpdGlvbjogLTI2cHggMDtcbn1cblxuLnN0YXJzLTMtNSB7XG4gIGJhY2tncm91bmQtcG9zaXRpb246IC0xM3B4IC0xOXB4O1xufVxuXG4uc3RhcnMtNCB7XG4gIGJhY2tncm91bmQtcG9zaXRpb246IC0xM3B4IDA7XG59XG5cbi5zdGFycy00LTUge1xuICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiAwIC0xOHB4O1xufVxuXG4uc3RhcnMtNSB7XG4gIGJhY2tncm91bmQtcG9zaXRpb246IDAgMDtcbn1cblxuLnR2LWltYWdlIHtcbiAgbWFyZ2luLWxlZnQ6IDEwcHg7XG59XG5cbi50di1icmFuZCB7XG4gIGNvbG9yOiAjZDNkM2QzO1xuICBmb250LXNpemU6IDEzcHg7XG59XG5cbi50di1wcmljZSB7XG4gIGNvbG9yOiAjYjEyNzA0O1xufVxuXG4ubW9iaWxlLWZpbHRlci1lbnRyeSB7XG4gIGRpc3BsYXk6IG5vbmU7XG59XG5cbi5maWx0ZXItY29uZGl0aW9uIHtcbiAgYm9yZGVyOiAxcHggc29saWQgI2QzZDNkMztcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gIGZvbnQtc2l6ZTogMTZweDtcbiAgaGVpZ2h0OiAyNXB4O1xuICB0ZXh0LWFsaWduOiBjZW50ZXI7XG4gIHdpZHRoOiAxMDBweDtcbn1cbi5maWx0ZXItY29uZGl0aW9uIC5maWx0ZXItbGFiZWwge1xuICBtYXJnaW4tcmlnaHQ6IDVweDtcbn1cblxuLnNsaWNlciB7XG4gIG1hcmdpbjogMTBweCAwO1xufVxuXG4uc2xpY2VyLWl0ZW0ge1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIGRpc3BsYXk6IC13ZWJraXQtYm94O1xuICBkaXNwbGF5OiAtbXMtZmxleGJveDtcbiAgZGlzcGxheTogZmxleDtcbiAgbWFyZ2luOiAycHggMDtcbn1cbi5zbGljZXItaXRlbS5zZWxlY3RlZCB7XG4gIGNvbG9yOiAjMzM3YWI3O1xufVxuLnNsaWNlci1pdGVtLnNlbGVjdGVkIC5sYWJlbCB7XG4gIGZvbnQtd2VpZ2h0OiBib2xkO1xufVxuLnNsaWNlci1pdGVtOmhvdmVyIHtcbiAgY29sb3I6ICNlNDc5MTE7XG59XG4uc2xpY2VyLWl0ZW0uZmlsdGVyZWQge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmO1xufVxuLnNsaWNlci1pdGVtLmZpbHRlcmVkT3V0QnlPdGhlciB7XG4gIGNvbG9yOiAjYTZhOGIxO1xufVxuLnNsaWNlci1pdGVtLmZpbHRlcmVkT3V0QnlTZWxmIHtcbiAgYmFja2dyb3VuZC1jb2xvcjogI2ZmZjtcbn1cbi5zbGljZXItaXRlbSBpbnB1dCB7XG4gIG1hcmdpbi1yaWdodDogNHB4O1xufVxuLnNsaWNlci1pdGVtIC5jb3VudC1iYWRnZSB7XG4gIG1hcmdpbi1sZWZ0OiA0cHg7XG4gIGNvbG9yOiAjYTI5OTk5O1xufVxuXG5AbWVkaWEgb25seSBzY3JlZW4gYW5kIChtYXgtd2lkdGg6IDc2OHB4KSB7XG4gICNncmlkIHtcbiAgICBoZWlnaHQ6IDkwJTtcbiAgICBwb3NpdGlvbjogc3RhdGljO1xuICB9XG5cbiAgLmZpbHRlci1wYW5lbCB7XG4gICAgYmFja2dyb3VuZDogI2ZmZjtcbiAgICBib3JkZXI6IDFweCBzb2xpZCAjZDNkM2QzO1xuICAgIGRpc3BsYXk6IG5vbmU7XG4gICAgaGVpZ2h0OiBjYWxjKDEwMCUgLSAyNXB4KTtcbiAgICBtYXJnaW4tdG9wOiAtMXB4O1xuICAgIG92ZXJmbG93OiBhdXRvO1xuICAgIHBhZGRpbmc6IDVweCAwIDAgMTBweDtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgei1pbmRleDogMTtcbiAgfVxuXG4gIC5tb2JpbGUtZmlsdGVyLWVudHJ5IHtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBoZWlnaHQ6IDI1cHg7XG4gIH1cbn0iXX0= */
(function () { const IS_PROD = window.process.env.NODE_ENV === 'production'; const USE_NPM = window.process.env.USE_NPM; const USE_CDN = window.process.env.USE_CDN; const SITE_ROOT = window.process.env.SITE_ROOT; const FRAMEWORK = window.process.env.FRAMEWORK; const ext = IS_PROD ? '.min.js' : '.js'; function js(name) { return name + ext; } function npm(t) { if (!t.file) { t.file = IS_PROD ? t.prod : t.dev; } const version = USE_CDN && t.version ? '@' + t.version : ''; const path = t.pkg + version + '/' + t.file; if (USE_CDN) { return 'https://unpkg.com/' + path; } return 'npm:' + path; } function dv(t) { if (USE_CDN || USE_NPM) { t.file = 'dist/' + t.file + '.min.js'; return npm(t); } return SITE_ROOT + '/static/dataviews/' + js(t.file); } const isTypeScript = FRAMEWORK === 'angular'; const babelConfig = { es2015: true, react: true, }; const meta = { js: { babelOptions: babelConfig, }, ts: { typescriptOptions: { tsconfig: true }, }, }; const map = { // gc.dataviews packages '@grapecity/dataviews.common': dv({pkg:'@grapecity/dataviews.common',file:'gc.dataviews.common',version:'1.8.17'}), '@grapecity/dataviews.core': dv({pkg:'@grapecity/dataviews.core',file:'gc.dataviews.core',version:'1.8.17'}), '@grapecity/dataviews.grid': dv({pkg:'@grapecity/dataviews.grid',file:'gc.dataviews.grid',version:'1.8.17'}), '@grapecity/dataviews.cardlayout': dv({pkg:'@grapecity/dataviews.cardlayout',file:'gc.dataviews.cardlayout',version:'1.8.17'}), '@grapecity/dataviews.masonry': dv({pkg:'@grapecity/dataviews.masonry',file:'gc.dataviews.masonry',version:'1.8.17'}), '@grapecity/dataviews.calendar': dv({pkg:'@grapecity/dataviews.calendar',file:'gc.dataviews.calendar',version:'1.8.17'}), '@grapecity/dataviews.timeline': dv({pkg:'@grapecity/dataviews.timeline',file:'gc.dataviews.timeline',version:'1.8.17'}), '@grapecity/dataviews.trellis': dv({pkg:'@grapecity/dataviews.trellis',file:'gc.dataviews.trellis',version:'1.8.17'}), '@grapecity/dataviews.gantt': dv({pkg:'@grapecity/dataviews.gantt',file:'gc.dataviews.gantt',version:'1.8.17'}), '@grapecity/dataviews.searchbox': dv({pkg:'@grapecity/dataviews.searchbox',file:'gc.dataviews.searchbox',version:'1.8.17'}), '@grapecity/dataviews.react': dv({pkg:'@grapecity/dataviews.react',file:'gc.dataviews.react',version:'1.8.17'}), '@grapecity/dataviews.vue': dv({pkg:'@grapecity/dataviews.vue',file:'gc.dataviews.vue',version:'1.8.17'}), '@grapecity/dataviews.angular': dv({pkg:'@grapecity/dataviews.angular',file:'gc.dataviews.angular',version:'1.8.17'}), '@grapecity/dataviews.csvexport': dv({pkg:'@grapecity/dataviews.angular',file:'gc.dataviews.csvexport',version:'1.8.17'}), // third-party libs react: npm({pkg:'react',prod:'umd/react.production.min.js',dev:'umd/react.development.js',version:'16.13.1'}), 'react-dom': npm({pkg:'react-dom',prod:'umd/react-dom.production.min.js',dev:'umd/react-dom.development.js',version:'16.13.1'}), 'react-router-dom': npm({pkg:'react-router-dom',prod:'umd/react-router-dom.min.js',dev:'umd/react-router-dom.js',version:'5.2.0'}), 'vue': npm({pkg:'vue',file:'dist/vue.js',version:'2.6.12'}), 'vue-router': npm({pkg:'vue-router',file:'dist/vue-router.js',version:'3.4.3'}), 'lodash': npm({pkg: 'lodash', file: js('lodash')}), 'zone.js': npm({pkg: 'zone.js', file: js('dist/zone')}), 'rxjs': npm({pkg: 'rxjs', file: js('bundles/rxjs.umd')}), 'rxjs/operators': npm({pkg:'rxjs-operators-bundle',prod:'dist/bundle.min.js',dev:'dist/bundle.js',version:'1.0.2'}), '@angular/core': npm({pkg: '@angular/core', file: js('bundles/core.umd')}), '@angular/common': npm({pkg: '@angular/common', file: js('bundles/common.umd')}), '@angular/compiler': npm({pkg: '@angular/compiler', file: js('bundles/compiler.umd')}), '@angular/platform-browser': npm({pkg: '@angular/platform-browser', file: js('bundles/platform-browser.umd')}), '@angular/platform-browser-dynamic': npm({pkg: '@angular/platform-browser-dynamic', file: js('bundles/platform-browser-dynamic.umd')}), '@angular/http': npm({pkg: '@angular/http', file: js('bundles/http.umd')}), '@angular/common/http': npm({pkg: '@angular/common', file: js('bundles/common-http.umd')}), '@angular/router': npm({pkg: '@angular/router', file: js('bundles/router.umd')}), '@angular/forms': npm({pkg: '@angular/forms', file: js('bundles/forms.umd')}), // systemjs plugins 'systemjs-plugin-json': npm({pkg:'systemjs-plugin-json',file:'json.js',version:'0.3.0'}), 'systemjs-plugin-css': npm({pkg:'systemjs-plugin-css',file:'css.js',version:'0.1.37'}), 'systemjs-plugin-babel': npm({pkg:'systemjs-plugin-babel',file:'plugin-babel.js',version:'0.0.25'}), 'systemjs-babel-build': npm({pkg:'systemjs-plugin-babel',file:'systemjs-babel-browser.js',version:'0.0.25'}), 'plugin-typescript': npm({pkg:'plugin-typescript',file:'lib/plugin.js',version:'8.0.0'}), 'typescript': npm({pkg:'typescript',file:'lib/typescript.js',version:'4.0.2'}), 'systemjs-vue-browser': npm({pkg:'systemjs-vue-browser',file:'index.js',version:'1.0.11'}), }; const config = { defaultJSExtensions: true, transpiler: isTypeScript ? 'plugin-typescript' : 'systemjs-plugin-babel', typescriptOptions: { tsconfig: true }, meta: { '*.json': {loader: 'systemjs-plugin-json'}, '*.css': {loader: 'systemjs-plugin-css'}, '*.vue': {loader: 'systemjs-vue-browser'}, '*.js': meta.js, '*.ts': meta.ts, 'app.js': { format: 'esm', babelOptions: babelConfig, }, 'typescript': { exports: 'ts', }, '@grapecity/dataviews.common': { format: 'amd', }, '@grapecity/dataviews.core': { format: 'amd', deps: [ '@grapecity/dataviews.common', ], }, '@grapecity/dataviews.grid': { format: 'amd', deps: [ '@grapecity/dataviews.common', '@grapecity/dataviews.core', ], }, '@grapecity/dataviews.cardlayout': { format: 'amd', deps: [ '@grapecity/dataviews.common', ], }, '@grapecity/dataviews.masonry': { format: 'amd', deps: [ '@grapecity/dataviews.common', ], }, '@grapecity/dataviews.calendar': { format: 'amd', deps: [ '@grapecity/dataviews.common', '@grapecity/dataviews.core', ], }, '@grapecity/dataviews.timeline': { format: 'amd', deps: [ '@grapecity/dataviews.common', ], }, '@grapecity/dataviews.trellis': { format: 'amd', deps: [ '@grapecity/dataviews.common', ], }, '@grapecity/dataviews.gantt': { format: 'amd', deps: [ '@grapecity/dataviews.common', ], }, '@grapecity/dataviews.searchbox': { format: 'amd', deps: [ '@grapecity/dataviews.common', ], }, '@grapecity/dataviews.react': { format: 'amd', deps: [ 'react', '@grapecity/dataviews.common', '@grapecity/dataviews.core' ], }, '@grapecity/dataviews.vue': { format: 'amd', deps: [ 'vue', '@grapecity/dataviews.common', '@grapecity/dataviews.core' ], }, '@grapecity/dataviews.angular': { format: 'amd', deps: [ '@angular/core', '@grapecity/dataviews.common', '@grapecity/dataviews.core' ], }, '@grapecity/dataviews.csvexport': { format: 'amd', deps: [ '@grapecity/dataviews.common' ], }, }, paths: { // paths serve as alias 'npm:': SITE_ROOT + '/node_modules/', }, // map tells the System loader where to look for things map: map, // packages tells the System loader how to load when no filename and/or no extension packages: { '.': { defaultExtension: isTypeScript ? 'ts' : 'js' }, node_modules: { defaultExtension: 'js' }, } }; // fast format detection to avoid detection by source code using regexp Object.keys(map).filter(function (key) { return !config.meta[key]; }).forEach(function (key) { const path = map[key]; if (path.indexOf('/umd') >= 0 || path.indexOf('.umd') >= 0) { config.meta[key] = { format: 'amd' }; } if (path.indexOf('/cjs') >= 0) { config.meta[key] = { format: 'cjs' }; } }); System.config(config); })(this);