mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
Restructure accordion so list items are in their own component
Accordion styles to get more BEM
This commit is contained in:
parent
a7f5ef7b95
commit
3be4e80711
@ -4,7 +4,10 @@ import SilverStripeComponent from 'lib/SilverStripeComponent';
|
|||||||
class Accordion extends SilverStripeComponent {
|
class Accordion extends SilverStripeComponent {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div role="tablist" aria-multiselectable="true">{this.props.children}</div>
|
<div className="accordion"
|
||||||
|
role="tablist"
|
||||||
|
aria-multiselectable="true"
|
||||||
|
>{this.props.children}</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,48 @@
|
|||||||
// Accordion styles
|
// Accordion based off Bootstrap collapse
|
||||||
.accordion-group {
|
|
||||||
|
.accordion__block {
|
||||||
margin-top: $spacer-y * 1.25;
|
margin-top: $spacer-y * 1.25;
|
||||||
|
}
|
||||||
|
|
||||||
&__title {
|
.accordion__title {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
margin-left: -$spacer-y;
|
||||||
|
margin-right: -$spacer-y;
|
||||||
|
padding: $spacer-x*.75 $spacer-y;
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
line-height: $line-height-base;
|
||||||
|
font-weight: 400;
|
||||||
|
color: $body-color;
|
||||||
|
text-transform: uppercase;
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 1px solid $border-color;
|
||||||
|
|
||||||
a {
|
&::before {
|
||||||
/* Todo: extend table header */
|
padding: $spacer-x*.75 $spacer-y;
|
||||||
font-size: $font-size-sm;
|
position: absolute;
|
||||||
line-height: $line-height-base;
|
right: 0;
|
||||||
font-weight: 400;
|
top: 0;
|
||||||
text-transform: uppercase;
|
font-size: $font-size-lg;
|
||||||
padding: $spacer-x*.75 $spacer-y;
|
line-height: $line-height-base;
|
||||||
/* end table header */
|
color: lighten($body-color,30);
|
||||||
|
text-align: center;
|
||||||
|
content: "7";
|
||||||
|
font-family: silverstripe;
|
||||||
|
}
|
||||||
|
|
||||||
display: block;
|
&:hover,
|
||||||
margin-left: -$spacer-y;
|
&:active,
|
||||||
margin-right: -$spacer-y;
|
&:focus {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
position: relative;
|
|
||||||
border-bottom: 1px solid $border-color;
|
&::before {
|
||||||
color: $body-color;
|
color: $body-color;
|
||||||
|
|
||||||
&::before {
|
|
||||||
padding: $spacer-x*.75 $spacer-y;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
font-size: $font-size-lg;
|
|
||||||
line-height: $line-height-base;
|
|
||||||
color: lighten($body-color,30);
|
|
||||||
text-align: center;
|
|
||||||
content: "7";
|
|
||||||
font-family: silverstripe;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.collapsed::before {
|
|
||||||
content: "6";
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
color: $body-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.accordion__title.collapsed::before {
|
||||||
|
content: "6";
|
||||||
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
// TODO move list-group to its own component
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import SilverStripeComponent from 'lib/SilverStripeComponent';
|
import SilverStripeComponent from 'lib/SilverStripeComponent';
|
||||||
import 'bootstrap-collapse';
|
import 'bootstrap-collapse';
|
||||||
|
|
||||||
class AccordionGroup extends SilverStripeComponent {
|
class AccordionBlock extends SilverStripeComponent {
|
||||||
render() {
|
render() {
|
||||||
const headerID = `${this.props.groupid}_Header`;
|
const headerID = `${this.props.groupid}_Header`;
|
||||||
const listID = `${this.props.groupid}_Items`;
|
const listID = `${this.props.groupid}_Items`;
|
||||||
@ -15,12 +17,16 @@ class AccordionGroup extends SilverStripeComponent {
|
|||||||
'aria-labelledby': headerID,
|
'aria-labelledby': headerID,
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className="accordion-group">
|
<div className="accordion__block">
|
||||||
<h6 className="accordion-group__title" role="tab" id={headerID}>
|
<a className="accordion__title"
|
||||||
<a data-toggle="collapse" href={href} aria-expanded="true" aria-controls={listID}>
|
data-toggle="collapse"
|
||||||
{this.props.title}
|
href={href}
|
||||||
</a>
|
aria-expanded="true"
|
||||||
</h6>
|
aria-controls={listID}
|
||||||
|
id={headerID}
|
||||||
|
role="tab"
|
||||||
|
>{this.props.title}
|
||||||
|
</a>
|
||||||
<div {...groupProps}>
|
<div {...groupProps}>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</div>
|
</div>
|
||||||
@ -28,4 +34,4 @@ class AccordionGroup extends SilverStripeComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export default AccordionGroup;
|
export default AccordionBlock;
|
3
admin/client/src/components/Accordion/README.md
Normal file
3
admin/client/src/components/Accordion/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Accordion
|
||||||
|
|
||||||
|
The ability to have panel(s) which can collapse and expand
|
96
admin/client/src/components/ListGroup/LIstGroup.scss
Normal file
96
admin/client/src/components/ListGroup/LIstGroup.scss
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// List-group, based on Bootstraps list-group
|
||||||
|
// TODO split out campaign specific css from generic list-group
|
||||||
|
|
||||||
|
.list-group {
|
||||||
|
margin-left: -$spacer-y;
|
||||||
|
margin-right: -$spacer-y;
|
||||||
|
border-bottom: 1px solid $border-color-light;
|
||||||
|
margin-bottom: $spacer-y*.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item {
|
||||||
|
padding-left: $spacer-y;
|
||||||
|
padding-right: $spacer-y;
|
||||||
|
min-height: 64px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
.list-group-item--has-links {
|
||||||
|
display: block;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: $brand-primary;
|
||||||
|
color: #FFF;
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
|
.list-group-item--has-links,
|
||||||
|
.list-group-item__status {
|
||||||
|
color: #FFF;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item__heading {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 2px 0 5px;
|
||||||
|
color: $body-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item__thumbnail {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
display: block;
|
||||||
|
background: #ccc;
|
||||||
|
float: left;
|
||||||
|
margin: -12px 12px 0 -$spacer-y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show linked items
|
||||||
|
.list-group-item--has-links,
|
||||||
|
.list-group-item--is-linked {
|
||||||
|
color: $brand-primary;
|
||||||
|
float: right;
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
position: absolute;
|
||||||
|
right: $spacer-y;
|
||||||
|
top: 27px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity .2s ease-in-out;
|
||||||
|
|
||||||
|
.font-icon-link {
|
||||||
|
font-size: 16px;
|
||||||
|
position: relative;
|
||||||
|
top: 3px;
|
||||||
|
margin-right: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item--published {
|
||||||
|
opacity: .6;
|
||||||
|
transition: opacity .2s ease-in-out;
|
||||||
|
|
||||||
|
.list-group-item__status {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity .2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
|
.list-group-item__status {
|
||||||
|
display: inline-block;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
|
// TODO move to its own component list-group
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import SilverStripeComponent from 'lib/SilverStripeComponent';
|
import SilverStripeComponent from 'lib/SilverStripeComponent';
|
||||||
|
|
||||||
class AccordionItem extends SilverStripeComponent {
|
class ListGroupItem extends SilverStripeComponent {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@ -24,9 +26,9 @@ class AccordionItem extends SilverStripeComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AccordionItem.propTypes = {
|
ListGroupItem.propTypes = {
|
||||||
handleClickArg: React.PropTypes.any,
|
handleClickArg: React.PropTypes.any,
|
||||||
handleClick: React.PropTypes.func,
|
handleClick: React.PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AccordionItem;
|
export default ListGroupItem;
|
0
admin/client/src/components/ListGroup/README.md
Normal file
0
admin/client/src/components/ListGroup/README.md
Normal file
@ -1,118 +1 @@
|
|||||||
.campaign-items {
|
|
||||||
|
|
||||||
.list-group {
|
|
||||||
margin-left: -$spacer-y;
|
|
||||||
margin-right: -$spacer-y;
|
|
||||||
border-bottom: 1px solid $border-color-light;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-group-item {
|
|
||||||
padding-left: $spacer-y;
|
|
||||||
padding-right: $spacer-y;
|
|
||||||
min-height: 64px;
|
|
||||||
cursor: pointer;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
.list-group-item--has-links {
|
|
||||||
display: block;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline-width: 1px;
|
|
||||||
outline-offset: -1px;
|
|
||||||
outline-style: solid;
|
|
||||||
outline-color: $brand-primary;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background-color: $brand-primary;
|
|
||||||
color: #FFF;
|
|
||||||
opacity: 1;
|
|
||||||
|
|
||||||
.list-group-item--has-links,
|
|
||||||
.list-group-item__status {
|
|
||||||
color: #FFF;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Focus color clashes with selected colour
|
|
||||||
&:focus {
|
|
||||||
outline-color: darken($brand-primary, 10%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-group-item-heading {
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 14px;
|
|
||||||
margin: 2px 0 5px;
|
|
||||||
color: $body-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-group-item__thumbnail {
|
|
||||||
width: 64px;
|
|
||||||
height: 64px;
|
|
||||||
display: block;
|
|
||||||
background: #ccc;
|
|
||||||
float: left;
|
|
||||||
// See negate padding on bootstrap .list-group-item in _list-group.scss
|
|
||||||
margin: -12px 12px 0 (0 - $spacer-y);
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-size: 10px;
|
|
||||||
font-weight: 400;
|
|
||||||
letter-spacing: .4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show linked items
|
|
||||||
.list-group-item--has-links,
|
|
||||||
.list-group-item--is-linked {
|
|
||||||
color: $brand-primary;
|
|
||||||
float: right;
|
|
||||||
font-size: $font-size-sm;
|
|
||||||
position: absolute;
|
|
||||||
right: $spacer-y;
|
|
||||||
top: 27px;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity .2s ease-in-out;
|
|
||||||
|
|
||||||
.font-icon-link {
|
|
||||||
font-size: 16px;
|
|
||||||
position: relative;
|
|
||||||
top: 3px;
|
|
||||||
margin-right: 1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-group-item--published {
|
|
||||||
opacity: .6;
|
|
||||||
transition: opacity .2s ease-in-out;
|
|
||||||
|
|
||||||
.list-group-item__status {
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity .2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
opacity: 1;
|
|
||||||
|
|
||||||
.list-group-item__status {
|
|
||||||
display: inline-block;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -5,8 +5,8 @@ import * as recordActions from 'state/records/RecordsActions';
|
|||||||
import * as campaignActions from 'state/campaign/CampaignActions';
|
import * as campaignActions from 'state/campaign/CampaignActions';
|
||||||
import SilverStripeComponent from 'lib/SilverStripeComponent';
|
import SilverStripeComponent from 'lib/SilverStripeComponent';
|
||||||
import Accordion from 'components/Accordion/Accordion';
|
import Accordion from 'components/Accordion/Accordion';
|
||||||
import AccordionGroup from 'components/Accordion/AccordionGroup';
|
import AccordionBlock from 'components/Accordion/AccordionBlock';
|
||||||
import AccordionItem from 'components/Accordion/AccordionItem';
|
import ListGroupItem from 'components/ListGroup/ListGroupItem';
|
||||||
import Toolbar from 'components/Toolbar/Toolbar';
|
import Toolbar from 'components/Toolbar/Toolbar';
|
||||||
import FormAction from 'components/FormAction/FormAction';
|
import FormAction from 'components/FormAction/FormAction';
|
||||||
import CampaignAdminItem from './CampaignAdminItem';
|
import CampaignAdminItem from './CampaignAdminItem';
|
||||||
@ -49,12 +49,13 @@ class CampaignAdminList extends SilverStripeComponent {
|
|||||||
const itemGroups = this.groupItemsForSet();
|
const itemGroups = this.groupItemsForSet();
|
||||||
|
|
||||||
// Get items in this set
|
// Get items in this set
|
||||||
let accordionGroups = [];
|
let accordionBlocks = [];
|
||||||
|
|
||||||
Object.keys(itemGroups).forEach(className => {
|
Object.keys(itemGroups).forEach(className => {
|
||||||
const group = itemGroups[className];
|
const group = itemGroups[className];
|
||||||
const groupCount = group.items.length;
|
const groupCount = group.items.length;
|
||||||
|
|
||||||
let accordionItems = [];
|
let listGroupItems = [];
|
||||||
let title = `${groupCount} ${groupCount === 1 ? group.singular : group.plural}`;
|
let title = `${groupCount} ${groupCount === 1 ? group.singular : group.plural}`;
|
||||||
let groupid = `Set_${campaignId}_Group_${className}`;
|
let groupid = `Set_${campaignId}_Group_${className}`;
|
||||||
|
|
||||||
@ -86,18 +87,23 @@ class CampaignAdminList extends SilverStripeComponent {
|
|||||||
itemClassNames.push('active');
|
itemClassNames.push('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
accordionItems.push(
|
listGroupItems.push(
|
||||||
<AccordionItem key={item.ID} className={itemClassNames.join(' ')} handleClick={this.handleItemSelected} handleClickArg={item.ID} >
|
<ListGroupItem
|
||||||
|
key={item.ID}
|
||||||
|
className={itemClassNames.join(' ')}
|
||||||
|
handleClick={this.handleItemSelected}
|
||||||
|
handleClickArg={item.ID}
|
||||||
|
>
|
||||||
<CampaignAdminItem item={item} campaign={this.props.record} />
|
<CampaignAdminItem item={item} campaign={this.props.record} />
|
||||||
</AccordionItem>
|
</ListGroupItem>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Merge into group
|
// Merge into group
|
||||||
accordionGroups.push(
|
accordionBlocks.push(
|
||||||
<AccordionGroup key={groupid} groupid={groupid} title={title}>
|
<AccordionBlock key={groupid} groupid={groupid} title={title}>
|
||||||
{accordionItems}
|
{listGroupItems}
|
||||||
</AccordionGroup>
|
</AccordionBlock>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -114,7 +120,7 @@ class CampaignAdminList extends SilverStripeComponent {
|
|||||||
</Toolbar>
|
</Toolbar>
|
||||||
<div className="container-fluid campaign-items panel-scrollable--double-toolbar">
|
<div className="container-fluid campaign-items panel-scrollable--double-toolbar">
|
||||||
<Accordion>
|
<Accordion>
|
||||||
{accordionGroups}
|
{accordionBlocks}
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</div>
|
</div>
|
||||||
<div className="toolbar--south">
|
<div className="toolbar--south">
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
// Components
|
// Components
|
||||||
@import "../components/Accordion/Accordion";
|
@import "../components/Accordion/Accordion";
|
||||||
|
@import "../components/ListGroup/ListGroup";
|
||||||
@import "../components/Breadcrumb/Breadcrumb";
|
@import "../components/Breadcrumb/Breadcrumb";
|
||||||
@import "../components/FormAction/FormAction";
|
@import "../components/FormAction/FormAction";
|
||||||
@import "../components/GridField/GridField";
|
@import "../components/GridField/GridField";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user