CSS updates to Campaign Admin

refactored breadcrumbs to use bootstrap
fix border lines on table
Layout variables updated for spacing, added toolbar heights
Added as part of campaigns as this area needs to use these variables.
Added action toolbar for content, swapped values to variables
toolbar action spacing
Adjustments of breadcrumb variable
Move accordion styles to its own component
Campaign items, styles for linked items and state badges
Small update to class name
Class name updates, convert values into variables
This commit is contained in:
Paul Clarke 2016-04-11 18:43:46 +12:00 committed by Ingo Schommer
parent 2e90035771
commit 40c98c6047
19 changed files with 439 additions and 328 deletions

View File

@ -87,8 +87,7 @@ class CampaignAdmin extends LeftAndMain implements PermissionProvider {
"action": "admin\/campaigns\/EditForm",
"method": "POST",
"enctype": "multipart\/form-data",
"target": null,
"class": "cms-edit-form CampaignAdmin LeftAndMain"
"target": null
},
"data": [],
"fields": [{

View File

@ -0,0 +1,53 @@
// Accordion styles
.accordion-group {
margin-top: $spacer-y;
&__title {
margin-bottom: 0;
a {
/* Todo: extend table header */
font-size: $font-size-sm;
line-height: $line-height-base;
font-weight: 400;
text-transform: uppercase;
padding: $spacer-x*.75 $spacer-y;
/* end table header */
display: block;
margin-left: -$spacer-y;
margin-right: -$spacer-y;
text-decoration: none;
position: relative;
border-bottom: 1px solid #ddd;
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;
}
}
}
}
}

View File

@ -9,7 +9,7 @@ The breadcrumbs for the current section of the CMS.
An array of objects, each object should have a `text` and `href` key.
```
import NorthHeaderBreadcrumbsComponent from 'north-header-breadcrumbs';
import BreadcrumbComponent from 'breadcrumb';
...
@ -29,7 +29,7 @@ getBreadcrumbs() {
}
render() {
return <NorthHeaderBreadcrumbsComponent crumbs={this.getBreadcrumbs()} />
return <BreadcrumbComponent crumbs={this.getBreadcrumbs()} />
}
...

View File

@ -0,0 +1,39 @@
import React from 'react';
import SilverStripeComponent from 'silverstripe-component';
class BreadcrumbComponent extends SilverStripeComponent {
render() {
const classNames = ['breadcrumb'];
if (this.props.multiline) {
classNames.push('breadcrumb--multiline');
}
const classNamesStr = classNames.join(' ');
return (
<ol className={classNamesStr}>
{this.getBreadcrumbs()}
</ol>
);
}
getBreadcrumbs() {
if (typeof this.props.crumbs === 'undefined') {
return null;
}
return [].concat(
this.props.crumbs.slice(0, -1).map((crumb, index) => [
<li><a key={index} className="" href={crumb.href}>{crumb.text}</a></li>,
]),
this.props.crumbs.slice(-1).map((crumb, index) => [
<li className="active">
<h2 className="breadcrumb__crumb--last" key={index}>{crumb.text}</h2>
</li>,
])
);
}
}
export default BreadcrumbComponent;

View File

@ -0,0 +1,26 @@
.breadcrumb {
font-size: $font-size-xs;
line-height: 16px;
> .active {
float: none;
}
.breadcrumb__crumb--last {
font-size: $font-size-xs;
margin: 0;
font-weight: normal;
display: inline;
line-height: 16px;
}
}
.breadcrumb--multiline {
margin-bottom: 0;
.breadcrumb__crumb--last {
font-size: $font-size-lg;
display: block;
line-height: 22px;
}
}

View File

@ -1,13 +1,13 @@
.grid-field-action-component {
background: none;
border: 0;
color: $gray-dark;
padding: 0 8px;
color: $body-color;
padding: 0 $spacer-x/2;
height: 20px;
vertical-align: top;
&:hover {
color: darken($gray-dark, 10%);
color: darken($body-color, 10%);
}
&::before {
@ -17,15 +17,25 @@
.grid-field-cell-component {
display: table-cell;
padding: $grid-y*2 $grid-x*2;
padding: $spacer-y $spacer-x;
line-height: 20px;
&:first-child {
padding-left: $grid-x*2.5;
padding-left: #{$spacer-x + $spacer-x*.25};
}
&:last-child {
padding-right: $grid-x*2.5;
padding-right: #{$spacer-x + $spacer-x*.25};
width: 1px;
span { // TEMP, remove commas in js
display: none;
}
}
&:nth-child(2) {
text-align: center;
width: 1px;
}
&[data-reactid$=actionPlaceholder] {
@ -39,9 +49,9 @@
.grid-field-header-cell-component {
text-transform: uppercase;
font-size: $font-size-root - 1;
font-size: $font-size-sm;
display: table-cell;
padding: $grid-y*2 $grid-x*2;
padding: $spacer-y $spacer-x;
line-height: 20px;
&:first-child {
@ -50,20 +60,24 @@
&:last-child {
padding-right: $grid-x*2.5;
width: 1px !important;
}
}
.grid-field-table-component {
border-collapse: collapse;
li.grid-field-row-component {
display: table-row;
border: 0;
box-shadow: inset 0 -1px 0 0 $gray-lighter;
border-bottom: 1px solid $border-color;
margin: 0;
padding: 0;
// Header row
&:first-child {
background: none;
border-bottom: 1px solid $border-color;
}
// Drillable rows highlight on hover

View File

@ -1,36 +0,0 @@
import React from 'react';
import SilverStripeComponent from 'silverstripe-component';
class NorthHeaderBreadcrumbsComponent extends SilverStripeComponent {
render() {
return (
<div className="cms-content-header-info">
<div className="breadcrumbs-wrapper">
<h2 id="page-title-heading">
{this.getBreadcrumbs()}
</h2>
</div>
</div>
);
}
getBreadcrumbs() {
if (typeof this.props.crumbs === 'undefined') {
return null;
}
return [].concat(
this.props.crumbs.slice(0, -1).map((crumb, index) => [
<a key={index} className="cms-panel-link crumb" href={crumb.href}>{crumb.text}</a>,
<span className="sep">/</span>,
]),
this.props.crumbs.slice(-1).map((crumb, index) => [
<span key={index} className="crumb last">{crumb.text}</span>,
])
);
}
}
export default NorthHeaderBreadcrumbsComponent;

View File

@ -1,5 +0,0 @@
.breadcrumbs-wrapper {
.sep {
margin: 0 4px;
}
}

View File

@ -1,30 +1,18 @@
import React from 'react';
import NorthHeaderBreadcrumbsComponent from '../north-header-breadcrumbs/index';
import SilverStripeComponent from 'silverstripe-component';
class NorthHeaderComponent extends SilverStripeComponent {
render() {
return (
<div className="north-header-component">
<NorthHeaderBreadcrumbsComponent crumbs={this.getBreadcrumbs()} />
<div className="north-header">
<div className="north-header__navigation">
{this.props.children}
</div>
</div>
);
}
getBreadcrumbs() {
return [
{
text: 'Campaigns',
href: 'admin/campaigns',
},
{
text: 'March release',
href: 'admin/campaigns/show/1',
},
];
}
}
export default NorthHeaderComponent;

View File

@ -1,4 +1,25 @@
.north-header-component {
@extend .cms-content-header;
.north-header {
border-bottom: 1px solid $border-color-dark;
background-color: $background-north;
width: 100%;
height: $navbar-total-height;
z-index: 60;
.north-header__navigation { // Typically to hold breadcrumbs and back button
float: left;
padding: 0 $spacer-y;
max-width: 70%;
max-height: $navbar-height;
}
.north-header__heading {
font-size: $font-size-lg;
font-weight: normal;
line-height: 20px;
width: 100%;
}
.north-header__actions { // To hold things like search icon and view toggle
}
}

View File

@ -61,13 +61,21 @@ class CampaignAdminContainer extends SilverStripeComponent {
return (
<div className="cms-middle no-preview">
<div className="cms-campaigns collapse in" aria-expanded="true">
<NorthHeader />
<FormAction
label={i18n._t('Campaigns.ADDCAMPAIGN')}
icon={'plus-circled'}
handleClick={this.addCampaign}
/>
<FormBuilder schemaUrl={schemaUrl} createFn={this.createFn} />
<NorthHeader>
<h2 className="text-truncate north-header__heading">Campaigns</h2>
</NorthHeader>
<div className="cms-middle__scrollable">
<div className="content-toolbar">
<div className="btn-toolbar">
<FormAction
label={i18n._t('Campaigns.ADDCAMPAIGN')}
icon={'plus'}
handleClick={this.addCampaign}
/>
</div>
</div>
<FormBuilder schemaUrl={schemaUrl} createFn={this.createFn} />
</div>
</div>
</div>
);
@ -83,6 +91,7 @@ class CampaignAdminContainer extends SilverStripeComponent {
campaignId: this.props.campaignId,
itemListViewEndpoint: this.props.sectionConfig.itemListViewEndpoint,
publishApi: this.publishApi,
breadcrumbs: this.getBreadcrumbs(),
};
return (
@ -129,6 +138,19 @@ class CampaignAdminContainer extends SilverStripeComponent {
return <Component key={props.name} {...props} />;
}
getBreadcrumbs() {
return [
{
text: 'Campaigns',
href: 'admin/campaigns',
},
{
text: 'March release',
href: 'admin/campaigns/show/1',
},
];
}
/**
* Gets preview URL for itemid
* @param int id

View File

@ -19,38 +19,44 @@ class CampaignItem extends SilverStripeComponent {
if (campaign.State === 'open') {
switch (item.ChangeType) {
case 'created':
badge.className = 'label label-warning';
badge.className = 'label label-warning list-group-item__status';
badge.Title = i18n._t('CampaignItem.DRAFT', 'Draft');
break;
case 'modified':
badge.className = 'label label-warning';
badge.className = 'label label-warning list-group-item__status';
badge.Title = i18n._t('CampaignItem.MODIFIED', 'Modified');
break;
case 'deleted':
badge.className = 'label label-error';
badge.className = 'label label-error list-group-item__status';
badge.Title = i18n._t('CampaignItem.REMOVED', 'Removed');
break;
case 'none':
default:
badge.className = 'label label-success item_visible-hovered';
badge.className = 'label label-success list-group-item__status';
badge.Title = i18n._t('CampaignItem.NO_CHANGES', 'No changes');
break;
}
}
// Linked items
let links = <span className="list-group-item__linked item_visible-hovered">[lk] 3 links</span>;
let links = (
<span className="list-group-item--haslinks">
<i className="font-icon-link"></i>
3 linked items
</span>
);
// Thumbnail
if (item.Thumbnail) {
thumbnail = <span className="item__thumbnail"><img src={item.Thumbnail} /></span>;
thumbnail = <span className="list-group-item__thumbnail"><img src={item.Thumbnail} /></span>;
}
return (
<div>
{thumbnail}
<h4 className="list-group-item-heading">{item.Title}</h4>
<h4 className="list-group-item__heading">{item.Title}</h4>
<span className="list-group-item--islinked"><i className="font-icon-link"></i></span>
{links}
{badge.className && badge.Title &&
<span className={badge.className}>{badge.Title}</span>

View File

@ -10,6 +10,7 @@ import AccordionItem from 'components/accordion/item';
import NorthHeader from 'components/north-header/index';
import FormAction from 'components/form-action/index';
import CampaignItem from './item';
import BreadcrumbComponent from 'components/breadcrumb/index';
import CampaignPreview from './preview';
import i18n from 'i18n';
@ -83,7 +84,9 @@ class CampaignListContainer extends SilverStripeComponent {
return (
<div className={classNames}>
<div className="cms-campaigns collapse in" aria-expanded="true">
<NorthHeader />
<NorthHeader>
<BreadcrumbComponent crumbs={this.props.breadcrumbs} multiline />
</NorthHeader>
<div className="col-md-12 campaign-items">
<Accordion>
{accordionGroups}

View File

@ -1,210 +1,121 @@
.CampaignAdmin {
overflow-y: auto;
display: block;
// Contains campaign form and preview layout
.cms-middle {
padding-left: 0;
height: 100%;
position: relative;
transition: padding .2s;
&.with-preview {
@media (min-width: 992px) { /* lg */
padding-left: 316px;
.cms-campaigns {
width: 316px;
}
}
@media (min-width: 1200px) { /* xl */
padding-left: 448px;
.cms-campaigns {
width: 448px;
}
}
}
}
/* CAMPAIGNS */
.cms-campaigns {
width: 100%;
position: absolute;
left: 0;
top: 0;
height: 100%;
overflow: hidden;
background-color: #f6f7f8;
z-index: 2;
transition: width .2s;
padding-bottom: 53px;
.campaign-items {
height: calc(100% - 53px);
margin-bottom: 40px;
overflow: auto;
h4 {
font-weight: 400;
font-size: 14px;
margin: 2px 0 5px;
}
.list-group {
margin-left: -0.9375rem;
margin-right: -0.9375rem;
border-bottom: 1px solid #ddd;
margin-bottom: .75rem;
.list-group-item {
padding-left: 0.9375rem; /* would normally be set in variables as 20px */
padding-right: 0.9375rem;
min-height: 64px;
cursor: pointer;
text-decoration: none;
&:first-child {
border-top: none;
}
.item__thumbnail {
width: 64px;
height: 64px;
display: block;
background: #ccc;
float: left;
margin: -12px 12px 0 -12px;
}
.label {
text-transform: uppercase;
font-size: 10px;
font-weight: 400;
letter-spacing: .4px;
}
// On hover show all linked items
.list-group-item__linked {
color: $body-color;
float: right;
}
}
}
}
}
// Hover items
.list-group-item--published {
opacity: .6;
}
.list-group-item--published:hover {
opacity: 1;
}
.item_visible-hovered {
opacity: 0;
transition: opacity .2s ease-in-out;
}
a:hover .item_visible-hovered,
a.active.list-group-item--published,
a.active.list-group-item--published .item_visible-hovered {
opacity: 1;
}
// Accordion styles
.accordion-group {
margin-top: 16px;
&__title {
margin-bottom: 0;
a {
font-size: 12px; /* extend table header */
font-weight: 400;
text-transform: uppercase;
padding: 1rem 0.9375rem;
display: block;
margin-left: -0.9375rem;
margin-right: -0.9375rem;
color: #555;
text-decoration: none;
position: relative;
border-bottom: 1px solid #ddd;
&::before {
content: "-";
width: 44px;
height: 44px;
padding: 10px 0.9375rem;
position: absolute;
right: 0;
top: 0;
font-size: 16px;
line-height: 20px;
text-align: center;
}
&.collapsed::before {
content: "+";
}
}
}
}
// TO MOVE
/* Preview panel */
.pages-preview {
display: block;
position: relative;
background-color: #BBB;
border-left: 1px solid #dbdde0;
height: 100%;
iframe {
width: 100%;
height: calc(100% - 53px);
border: none;
}
}
///* btn toolbar */
//.cms-south-actions {
// height: 53px;
// position: absolute;
// bottom: 0;
// width: 100%;
// border-top: 1px solid #ddd;
// background-color: #f6f7f8;
// padding: 8px 15px;
//}
//.btn-toolbar {
//
//}
//.btn-toolbar .btn {
// font-size: 13px;
// line-height: 20px;
//}
//
//
//.popover-content a {
// display: inline-block;
// width: 100%;
//}
//.icon-back {
// display: inline-block;
// margin-right: 12px;
//}
//.icon-back + h1 {
// display: inline-block;
//}
//
//.btn .label_empty {
// border-radius: 50%;
// height: 10px;
// width: 10px;
// top: 1px;
//}
// Changeset items
.cms-campaigns {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
overflow: hidden;
background-color: #f6f7f8;
z-index: 2;
transition: width .2s;
padding-bottom: $navbar-height +1; // incl border
}
.campaign-items {
height: 100%;
margin-bottom: 40px;
overflow-y: auto;
.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 {
min-height: 64px;
cursor: pointer;
text-decoration: none;
&:first-child {
border-top: none;
}
&__heading {
font-weight: 400;
font-size: 14px;
margin: 2px 0 5px;
color: $body-color;
}
&__thumbnail {
width: 64px;
height: 64px;
display: block;
background: #ccc;
float: left;
margin: -12px 12px 0 -$spacer-y;
}
.label {
text-transform: uppercase;
font-size: 10px;
font-weight: 400;
letter-spacing: .4px;
}
// Show linked items
&--haslinks,
&--islinked {
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;
}
}
&:hover {
text-decoration: none;
.list-group-item--haslinks {
display: block;
opacity: 1;
}
}
&.active {
background-color: $brand-primary;
color: #FFF;
opacity: 1;
.list-group-item--haslinks,
.list-group-item__status {
color: #FFF;
opacity: 1;
}
}
// Published 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;
}
}
}
}
}

View File

@ -1,9 +1,59 @@
.cms-south-actions { // Todo: update variables
height: 53px; // navbar-total-height
position: absolute;
bottom: 0;
width: 100%;
border-top: 1px solid #ddd; // $border-color
background-color: #f6f7f8; // $body-bg
padding: 10px 15px; // $spacer-y*.625 $spacer-x
.content-toolbar {
max-height: $navbar-height;
display: block;
padding: 10px 0 10px 12px;
margin-bottom: $spacer-y/2;
}
.cms-middle {
padding-left: 0;
height: 100%;
position: relative;
transition: padding .2s;
&.with-preview {
@media (min-width: 992px) { /* lg */
padding-left: 316px;
.cms-campaigns {
width: 316px;
}
}
@media (min-width: 1200px) { /* xl */
padding-left: 448px;
.cms-campaigns {
width: 448px;
}
}
}
}
.cms-middle__scrollable {
overflow-y: auto;
display: block;
height: 100%;
}
// Preview panel
.pages-preview {
display: block;
position: relative;
background-color: #BBB;
border-left: 1px solid #dbdde0;
height: 100%;
iframe {
width: 100%;
height: calc(100% - #{$navbar-total-height});
border: none;
}
}
//.cms-south-actions {
// height: $navbar-total-height;
// position: absolute;
// bottom: 0;
// width: 100%;
// border-top: 1px solid #ddd;
// background-color: #f6f7f8;
// padding: 8px 15px;
//}

View File

@ -1,13 +1,15 @@
// Components
/** -----------------------------
* Sections
* ------------------------------ */
@import "../sections/campaign-admin/styles";
/** -----------------------------
* Components
* ------------------------------ */
@import "../components/grid-field/styles";
@import "../components/north-header/styles";
@import "../components/north-header-breadcrumbs/styles";
@import "../components/breadcrumb/styles";
@import "../components/form-action/styles";
@import "../components/hidden-field/styles";
@import "../components/label/styles";
// Structural
@import "layout";
// Sections
@import "../sections/campaign-admin/styles";
@import "../components/accordion/styles";
@import "_layout.scss";

View File

@ -38,6 +38,16 @@ $brand-success: #3fa142;
// $brand-warning: #f0ad4e;
$brand-danger: #D40404;
// Backgrounds
$background-main: #f6f7f8;
$background-north: darken($background-main, 2);
// Borders
$border-color-light: darken($background-main, 6);
$border-color: darken($background-main, 10);
$border-color-dark: darken($background-main, 14);
// Options
//
@ -57,7 +67,7 @@ $brand-danger: #D40404;
// Control the default styling of most Bootstrap elements by modifying these
// variables. Mostly focused on spacing.
$spacer: 1rem;
$spacer: 1.2308rem; // 16px
$spacer-x: $spacer;
$spacer-y: $spacer;
$spacers: (
@ -135,7 +145,7 @@ $body-color: $gray-dark;
// Set the number of columns and specify the width of the gutters.
// $grid-columns: 12;
// $grid-gutter-width: 1.875rem; // 30px
$grid-gutter-width: 2.4615rem; // now 32px, was 1.875rem; ~ 30px
// Typography
@ -152,8 +162,9 @@ $font-size-root: 13px;
$font-size-base: 1rem;
$font-size-lg: 1.23rem; /* 16px */
$font-size-sm: .846rem; /* 11px */
$font-size-xs: .769rem; /* 10px */
$font-size-sm: .923rem; /* 12px */
$font-size-xs: .846rem; /* 11px */
$font-size-xxs: .769rem; /* 10px */
$font-size-h1: 2.5rem;
$font-size-h2: 18px; /* 2rem; */
@ -172,7 +183,8 @@ $font-size-h6: 12px; /* 1rem; */
// $display3-weight: 300;
// $display4-weight: 300;
$line-height: 1.538;
$line-height: 1.538; /* relative to font-size */
$line-height-base: 20px; /* can be used with varying font-sizes, holds grid sizing */
$headings-margin-bottom: $spacer;
// $headings-font-family: inherit;
@ -239,7 +251,7 @@ $text-muted: #7f8b97;
//
// For each of Bootstrap's buttons, define text, background and border color.
$btn-padding-x: 1.1rem;
$btn-padding-x: .6154rem; // 8px
$btn-padding-y: .3846rem;
$btn-font-weight: normal;
@ -370,6 +382,9 @@ $btn-danger-border: transparent;
// Navbar
$navbar-height: 52px;
$navbar-total-height: 53px;
// $navbar-border-radius: $border-radius;
// $navbar-padding-horizontal: $spacer;
// $navbar-padding-vertical: ($spacer / 2);
@ -627,13 +642,13 @@ $btn-danger-border: transparent;
// Breadcrumbs
// $breadcrumb-padding-vertical: .75rem;
// $breadcrumb-padding-horizontal: 1rem;
//
// $breadcrumb-bg: $gray-lighter;
// $breadcrumb-divider-color: $gray-light;
// $breadcrumb-active-color: $gray-light;
// $breadcrumb-divider: "/";
$breadcrumb-padding-vertical: 6px;
$breadcrumb-padding-horizontal: 0;
$breadcrumb-bg: transparent;
$breadcrumb-divider-color: $border-color-dark;
$breadcrumb-active-color: $body-color;
$breadcrumb-divider: "/";
// Carousel

View File

@ -273,8 +273,8 @@ gulp.task('bundle-lib', function bundleLib() {
.require(`${PATHS.ADMIN_JAVASCRIPT_SRC}/components/north-header/index`,
{ expose: 'components/north-header/index' }
)
.require(`${PATHS.ADMIN_JAVASCRIPT_SRC}/components/north-header-breadcrumbs/index`,
{ expose: 'components/north-header-breadcrumbs/index' }
.require(`${PATHS.ADMIN_JAVASCRIPT_SRC}/components/breadcrumb/index`,
{ expose: 'components/breadcrumb/index' }
)
.require(`${PATHS.FRAMEWORK_JAVASCRIPT_SRC}/i18n.js`,
{ expose: 'i18n' }
@ -297,6 +297,9 @@ gulp.task('bundle-lib', function bundleLib() {
.require(`${PATHS.ADMIN_JAVASCRIPT_SRC}/silverstripe-backend`,
{ expose: 'silverstripe-backend' }
)
.require(`${PATHS.MODULES}/bootstrap/dist/js/umd/collapse.js`,
{ expose: 'bootstrap-collapse' }
)
.bundle()
.on('error', notify.onError({ message: `${bundleFileName}: <%= error.message %>` }))
.pipe(source(bundleFileName))