shop: group cards
Closes #30 Co-authored-by: Egor Savkin <es@m-labs.hk> Co-committed-by: Egor Savkin <es@m-labs.hk>
This commit is contained in:
parent
d9ba17ad3a
commit
53a6d3f378
@ -12,6 +12,42 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#accordion_categories,
|
||||||
|
#accordion_categories .card {
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#accordion_categories .card:not(:first-child) {
|
||||||
|
border-top: thin rgba(255,255, 255, 20%) solid ;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#accordion_categories .card-header {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#accordion_categories button {
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.75rem;
|
||||||
|
padding: .75rem 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#accordion_categories .card .card-body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#accordion_categories .card-header:hover {
|
||||||
|
background-color: #1f4f68;
|
||||||
|
transition: 0.3s;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#accordion_categories button:focus,
|
||||||
|
#accordion_categories button:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
##Device = Tablets, Ipads (portrait)
|
##Device = Tablets, Ipads (portrait)
|
||||||
##Screen = B/w 768px to 1024px
|
##Screen = B/w 768px to 1024px
|
||||||
@ -110,6 +146,11 @@
|
|||||||
#root-shop .panel .summary>.summary-form {
|
#root-shop .panel .summary>.summary-form {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#accordion_categories button {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
padding: .75rem 1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
##Device = Tablets, Ipads (landscape)
|
##Device = Tablets, Ipads (landscape)
|
||||||
@ -178,6 +219,11 @@
|
|||||||
#root-shop .panel .summary>.summary-form {
|
#root-shop .panel .summary>.summary-form {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#accordion_categories button {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
padding: .75rem 1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
##Device = Low Resolution Tablets, Mobiles (Landscape)
|
##Device = Low Resolution Tablets, Mobiles (Landscape)
|
||||||
@ -379,6 +425,11 @@
|
|||||||
#root-shop .panel .summary>.summary-form {
|
#root-shop .panel .summary>.summary-form {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#accordion_categories button {
|
||||||
|
font-size: 1rem;
|
||||||
|
padding: .5rem 0.5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
##Device = Most of the Smartphones Mobiles (Portrait)
|
##Device = Most of the Smartphones Mobiles (Portrait)
|
||||||
@ -576,4 +627,9 @@
|
|||||||
#root-shop .panel .summary>.summary-form {
|
#root-shop .panel .summary>.summary-form {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#accordion_categories button {
|
||||||
|
font-size: 1rem;
|
||||||
|
padding: .5rem 0.5rem;
|
||||||
|
}
|
||||||
}
|
}
|
@ -74,15 +74,13 @@ const copy = (
|
|||||||
model,
|
model,
|
||||||
source,
|
source,
|
||||||
destination,
|
destination,
|
||||||
droppableSource,
|
draggableSource,
|
||||||
droppableDestination
|
droppableDestination
|
||||||
) => {
|
) => {
|
||||||
const sourceClone = Array.from(source.itemIds);
|
|
||||||
const destClone = Array.from(destination.items);
|
const destClone = Array.from(destination.items);
|
||||||
const item = sourceClone[droppableSource.index];
|
|
||||||
|
|
||||||
destClone.splice(droppableDestination.index, 0, {
|
destClone.splice(droppableDestination.index, 0, {
|
||||||
...model[item],
|
...model[draggableSource],
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -408,7 +406,6 @@ class ProductItem extends React.PureComponent {
|
|||||||
static get propTypes() {
|
static get propTypes() {
|
||||||
return {
|
return {
|
||||||
id: PropTypes.string.isRequired,
|
id: PropTypes.string.isRequired,
|
||||||
index: PropTypes.number.isRequired,
|
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
name_codename: PropTypes.string,
|
name_codename: PropTypes.string,
|
||||||
price: PropTypes.number.isRequired,
|
price: PropTypes.number.isRequired,
|
||||||
@ -426,9 +423,9 @@ class ProductItem extends React.PureComponent {
|
|||||||
this.handleOnClickAddItem = this.handleOnClickAddItem.bind(this);
|
this.handleOnClickAddItem = this.handleOnClickAddItem.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleOnClickAddItem(index, tap, e) {
|
handleOnClickAddItem(id, tap, e) {
|
||||||
if (this.props.onClickAddItem) {
|
if (this.props.onClickAddItem) {
|
||||||
this.props.onClickAddItem(index, tap);
|
this.props.onClickAddItem(id, tap);
|
||||||
}
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
@ -436,7 +433,6 @@ class ProductItem extends React.PureComponent {
|
|||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
index,
|
|
||||||
name,
|
name,
|
||||||
name_codename,
|
name_codename,
|
||||||
price,
|
price,
|
||||||
@ -482,11 +478,11 @@ class ProductItem extends React.PureComponent {
|
|||||||
|
|
||||||
<div className="content">
|
<div className="content">
|
||||||
|
|
||||||
<button onClick={this.handleOnClickAddItem.bind(this, index, true)}>
|
<button onClick={this.handleOnClickAddItem.bind(this, id, true)}>
|
||||||
<img src="/images/shop/icon-add.svg" alt="add" />
|
<img src="/images/shop/icon-add.svg" alt="add" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<Draggable draggableId={id} index={index}>
|
<Draggable draggableId={id}>
|
||||||
{(provided, snapshot) => (
|
{(provided, snapshot) => (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<img
|
<img
|
||||||
@ -1515,25 +1511,43 @@ class Backlog extends React.PureComponent {
|
|||||||
isMobile,
|
isMobile,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const ordered_items = data.itemIds.map(itemId => items[itemId]);
|
|
||||||
const products = ordered_items.map((item, index) => {
|
const ordered_groups = data.categories.map(groupItem => ({ name: groupItem.name,
|
||||||
return (
|
items: groupItem.itemIds.map(itemId => items[itemId])
|
||||||
<ProductItem
|
}));
|
||||||
key={item.id}
|
const groups = ordered_groups.map((group, g_index) => {
|
||||||
id={item.id}
|
return (
|
||||||
index={index}
|
<div className="card">
|
||||||
name={`${item.name_number} ${item.name}`}
|
<h2 className="card-header">
|
||||||
name_codename={item.name_codename}
|
<button className="btn btn-link btn-block text-left " type="button" data-toggle="collapse"
|
||||||
price={item.price}
|
data-target={`#collapse${g_index}`} aria-expanded="true" aria-controls={`collapse${g_index}`}>
|
||||||
currency={currency}
|
{group.name}
|
||||||
image={`/images/${item.image}`}
|
</button>
|
||||||
specs={item.specs}
|
</h2>
|
||||||
datasheet_file={item.datasheet_file}
|
<div id={`collapse${g_index}`} className="collapse" aria-labelledby="headingOne"
|
||||||
datasheet_name={item.datasheet_name}
|
data-parent="#accordion_categories">
|
||||||
onClickAddItem={onClickAddItem}
|
<div className="card-body">
|
||||||
></ProductItem>
|
{group.items.map(item => (
|
||||||
);
|
<ProductItem
|
||||||
});
|
key={item.id}
|
||||||
|
id={item.id}
|
||||||
|
name={`${item.name_number} ${item.name}`}
|
||||||
|
name_codename={item.name_codename}
|
||||||
|
price={item.price}
|
||||||
|
currency={currency}
|
||||||
|
image={`/images/${item.image}`}
|
||||||
|
specs={item.specs}
|
||||||
|
datasheet_file={item.datasheet_file}
|
||||||
|
datasheet_name={item.datasheet_name}
|
||||||
|
onClickAddItem={onClickAddItem}
|
||||||
|
></ProductItem>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Droppable
|
<Droppable
|
||||||
@ -1554,7 +1568,9 @@ class Backlog extends React.PureComponent {
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{products}
|
<div className="accordion" id="accordion_categories">
|
||||||
|
{groups}
|
||||||
|
</div>
|
||||||
|
|
||||||
{provided.placeholder && (
|
{provided.placeholder && (
|
||||||
<div style={{ display: 'none' }}>
|
<div style={{ display: 'none' }}>
|
||||||
@ -1608,9 +1624,10 @@ class Shop extends React.PureComponent {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
// index 0 is a Kasli, we place it as a default conf on the crate.
|
// index 0 is a Kasli, we place it as a default conf on the crate.
|
||||||
|
const sourceIds = Array.from(this.state.columns.backlog.categories.map(groupId => groupId.itemIds).flat())
|
||||||
const source = {
|
const source = {
|
||||||
droppableId: 'backlog',
|
droppableId: 'backlog',
|
||||||
index: 0,
|
index: null,
|
||||||
};
|
};
|
||||||
const destination = {
|
const destination = {
|
||||||
droppableId: 'cart',
|
droppableId: 'cart',
|
||||||
@ -1620,7 +1637,7 @@ class Shop extends React.PureComponent {
|
|||||||
this.handleOnDragEnd({
|
this.handleOnDragEnd({
|
||||||
source,
|
source,
|
||||||
destination,
|
destination,
|
||||||
draggableId: null,
|
draggableId: sourceIds[0],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1703,10 +1720,10 @@ class Shop extends React.PureComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClickAddItem(index, tap) {
|
handleClickAddItem(id, tap) {
|
||||||
const source = {
|
const source = {
|
||||||
droppableId: 'backlog',
|
droppableId: 'backlog',
|
||||||
index: index,
|
index: null,
|
||||||
};
|
};
|
||||||
const destination = {
|
const destination = {
|
||||||
droppableId: 'cart',
|
droppableId: 'cart',
|
||||||
@ -1716,7 +1733,7 @@ class Shop extends React.PureComponent {
|
|||||||
this.handleOnDragEnd({
|
this.handleOnDragEnd({
|
||||||
source,
|
source,
|
||||||
destination,
|
destination,
|
||||||
draggableId: null
|
draggableId: id
|
||||||
}, tap);
|
}, tap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1958,7 +1975,7 @@ class Shop extends React.PureComponent {
|
|||||||
this.state.items,
|
this.state.items,
|
||||||
this.state.columns[source.droppableId],
|
this.state.columns[source.droppableId],
|
||||||
this.state.columns[destination.droppableId],
|
this.state.columns[destination.droppableId],
|
||||||
source,
|
draggableId,
|
||||||
destination,
|
destination,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
612
static/js/shop.min.js
vendored
612
static/js/shop.min.js
vendored
File diff suppressed because it is too large
Load Diff
@ -855,28 +855,40 @@ const shop_data = {
|
|||||||
id: 'backlog',
|
id: 'backlog',
|
||||||
title: 'Backlog',
|
title: 'Backlog',
|
||||||
/* itemIds define items order - change order to suit your need */
|
/* itemIds define items order - change order to suit your need */
|
||||||
itemIds: [
|
categories: [
|
||||||
'kasli',
|
{ name: 'Core',
|
||||||
'kaslisoc',
|
itemIds: [
|
||||||
'bnc-dio',
|
'kasli',
|
||||||
'sma-dio',
|
'kaslisoc']},
|
||||||
'mcx-dio',
|
{ name: 'TTL',
|
||||||
'rj45-dio',
|
itemIds: [
|
||||||
'urukul',
|
'bnc-dio',
|
||||||
'phaser',
|
'sma-dio',
|
||||||
'mirny',
|
'mcx-dio',
|
||||||
'almazny',
|
'rj45-dio']},
|
||||||
'zotino',
|
{ name: 'RF',
|
||||||
'fastino',
|
itemIds: [
|
||||||
'idc-bnc-adapter',
|
'clocker',
|
||||||
'idc-sma-adapter',
|
'urukul',
|
||||||
'idc-mcx-adapter',
|
'phaser',
|
||||||
'hd68-idc-adapter',
|
'mirny',
|
||||||
'novo',
|
'almazny']},
|
||||||
'koster',
|
{ name: 'DAC/ADC',
|
||||||
'clocker',
|
itemIds: [
|
||||||
'stabilizer',
|
'zotino',
|
||||||
'vhdcicarrier',
|
'fastino',
|
||||||
|
'novo']},
|
||||||
|
{ name: 'Adapters',
|
||||||
|
itemIds: [
|
||||||
|
'idc-bnc-adapter',
|
||||||
|
'idc-sma-adapter',
|
||||||
|
'idc-mcx-adapter',
|
||||||
|
'hd68-idc-adapter',
|
||||||
|
'vhdcicarrier']},
|
||||||
|
{ name: 'Misc',
|
||||||
|
itemIds: [
|
||||||
|
'koster',
|
||||||
|
'stabilizer']}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user