es6 classes for React; closes #112
This commit is contained in:
parent
b57bc76edd
commit
c3896a3598
6
.babelrc
6
.babelrc
|
@ -1,3 +1,7 @@
|
|||
{
|
||||
"presets": [ "react", "es2015" ]
|
||||
"presets": [
|
||||
"react",
|
||||
"es2015",
|
||||
"stage-0"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "burnchart",
|
||||
"version": "3.2.1",
|
||||
"version": "3.2.2",
|
||||
"description": "GitHub Burndown Chart as a Service",
|
||||
"author": "Radek Stepan <dev@radekstepan.com> (http://radekstepan.com)",
|
||||
"license": "AGPL-3.0",
|
||||
|
@ -21,6 +21,7 @@
|
|||
"babel": "^6.3.26",
|
||||
"babel-preset-es2015": "^6.3.13",
|
||||
"babel-preset-react": "^6.3.13",
|
||||
"babel-preset-stage-0": "^6.5.0",
|
||||
"babel-register": "^6.4.3",
|
||||
"babelify": "^7.2.0",
|
||||
"browserify": "^13.0.0",
|
||||
|
|
|
@ -1060,5 +1060,5 @@ ul li {
|
|||
color: #C1041C;
|
||||
}
|
||||
#app.theme--monza #page #content #projects table tr td.action {
|
||||
background: #760211;
|
||||
color: #760211;
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
2454
public/js/bundle.js
2454
public/js/bundle.js
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -27,8 +27,8 @@ export default {
|
|||
},
|
||||
// Request pertaining.
|
||||
"request": {
|
||||
// Default timeout of 5s.
|
||||
"timeout": 5e3
|
||||
// Default timeout of 10s.
|
||||
"timeout": 1e4
|
||||
},
|
||||
// The app theme; 'monza' is the default red theme.
|
||||
"theme": "monza"
|
||||
|
|
|
@ -39,13 +39,13 @@ let find = ({ to, params, query }) => {
|
|||
_.find(routes, (name, url) => {
|
||||
if (name != to) return;
|
||||
let matches = url.match(re);
|
||||
|
||||
|
||||
// Do not match on the number of params.
|
||||
if (_.keys(params).length != (matches || []).length) return;
|
||||
|
||||
|
||||
// Do not match on the name of params.
|
||||
if (!_.every(matches, m => m.slice(1) in params)) return;
|
||||
|
||||
|
||||
// Fill in the params.
|
||||
$url = url.replace(re, m => params[m.slice(1)]);
|
||||
|
||||
|
|
|
@ -8,33 +8,42 @@ import actions from '../actions/appActions.js';
|
|||
import Icon from './Icon.jsx';
|
||||
import S from './Space.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
export default class AddProjectForm extends React.Component {
|
||||
|
||||
displayName: 'AddProjectForm.jsx',
|
||||
displayName: 'AddProjectForm.jsx'
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
// Blank input.
|
||||
this.state = { 'val': '' };
|
||||
// Bindings.
|
||||
this._onChange = this._onChange.bind(this);
|
||||
this._onAdd = this._onAdd.bind(this);
|
||||
}
|
||||
|
||||
// Sign user in.
|
||||
_onSignIn() {
|
||||
actions.emit('user.signin');
|
||||
},
|
||||
}
|
||||
|
||||
_onChange(evt, { newValue }) {
|
||||
this.setState({ 'val': newValue });
|
||||
},
|
||||
}
|
||||
|
||||
// Get a list of repo suggestions.
|
||||
_onGetList({ value }) {
|
||||
actions.emit('projects.search', value);
|
||||
},
|
||||
}
|
||||
|
||||
// What should be the value of the suggestion.
|
||||
_getListValue(value) {
|
||||
return value;
|
||||
},
|
||||
}
|
||||
|
||||
// How do we render the repo?
|
||||
_renderListValue(value) {
|
||||
return value;
|
||||
},
|
||||
}
|
||||
|
||||
// Add the project.
|
||||
_onAdd() {
|
||||
|
@ -46,12 +55,7 @@ export default React.createClass({
|
|||
actions.emit('projects.add', { owner, name });
|
||||
// Redirect to the dashboard.
|
||||
App.navigate({ 'to': 'projects' });
|
||||
},
|
||||
|
||||
// Blank input.
|
||||
getInitialState() {
|
||||
return { 'val': '' };
|
||||
},
|
||||
}
|
||||
|
||||
render() {
|
||||
let user;
|
||||
|
@ -106,11 +110,6 @@ export default React.createClass({
|
|||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
// Focus input field on mount.
|
||||
componentDidMount() {
|
||||
if ('el' in this.refs) this.refs.el.focus();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,13 +7,17 @@ d3Tip(d3);
|
|||
import lines from '../modules/chart/lines.js';
|
||||
import axes from '../modules/chart/axes.js';
|
||||
|
||||
export default React.createClass({
|
||||
export default class Chart extends React.Component {
|
||||
|
||||
displayName: 'Chart.jsx',
|
||||
displayName: 'Chart.jsx'
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div id="chart" ref="el" style={this.props.style} />;
|
||||
},
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let { data } = this.props;
|
||||
|
@ -154,4 +158,4 @@ export default React.createClass({
|
|||
.on('mouseout', tooltip.hide);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,13 +7,17 @@ import actions from '../actions/appActions.js';
|
|||
import Icon from './Icon.jsx';
|
||||
import Link from './Link.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
export default class EditProjects extends React.Component {
|
||||
|
||||
displayName: 'EditProjects.jsx',
|
||||
displayName: 'EditProjects.jsx'
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
_onDelete(project) {
|
||||
actions.emit('projects.delete', project);
|
||||
},
|
||||
}
|
||||
|
||||
render() {
|
||||
let { projects } = this.props;
|
||||
|
@ -55,4 +59,4 @@ export default React.createClass({
|
|||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
import React from 'react';
|
||||
|
||||
export default React.createClass({
|
||||
export default class Footer extends React.Component {
|
||||
|
||||
displayName: 'Footer.jsx',
|
||||
displayName: 'Footer.jsx'
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
|
@ -14,4 +18,4 @@ export default React.createClass({
|
|||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -6,24 +6,28 @@ import Notify from './Notify.jsx';
|
|||
import Icon from './Icon.jsx';
|
||||
import Link from './Link.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
export default class Header extends React.Component {
|
||||
|
||||
displayName: 'Header.jsx',
|
||||
displayName: 'Header.jsx'
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
// Sign user in.
|
||||
_onSignIn() {
|
||||
actions.emit('user.signin');
|
||||
},
|
||||
}
|
||||
|
||||
// Sign user out.
|
||||
_onSignOut() {
|
||||
actions.emit('user.signout');
|
||||
},
|
||||
}
|
||||
|
||||
// Add example projects.
|
||||
_onDemo() {
|
||||
actions.emit('projects.demo');
|
||||
},
|
||||
}
|
||||
|
||||
render() {
|
||||
// From app store.
|
||||
|
@ -79,4 +83,4 @@ export default React.createClass({
|
|||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,14 +5,18 @@ import actions from '../actions/appActions.js';
|
|||
import Icon from './Icon.jsx';
|
||||
import Link from './Link.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
export default class Hero extends React.Component {
|
||||
|
||||
displayName: 'Hero.jsx',
|
||||
displayName: 'Hero.jsx'
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
// Add example projects.
|
||||
_onDemo() {
|
||||
actions.emit('projects.demo');
|
||||
},
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
|
@ -35,4 +39,4 @@ export default React.createClass({
|
|||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import format from '../modules/format.js';
|
||||
|
||||
// Fontello icon hex codes.
|
||||
let codes = {
|
||||
const codes = {
|
||||
'delete': '\e800', // Font Awesome - trash-empty
|
||||
'settings': '\e801', // Font Awesome - cog
|
||||
'pencil': '\e802', // Font Awesome - pencil
|
||||
|
@ -20,18 +20,22 @@ let codes = {
|
|||
'megaphone': '\e80d', // Entypo - megaphone
|
||||
'sort': '\e80e', // Typicons - sort-alphabet
|
||||
'spinner': '\e80f', // MFG Labs - spinner1
|
||||
'fire': '\e810' // Maki - fire-station
|
||||
'fire': '\e810' // Maki - fire-station
|
||||
};
|
||||
|
||||
export default React.createClass({
|
||||
export default class Icon extends React.Component {
|
||||
|
||||
displayName: 'Icon.jsx',
|
||||
displayName: 'Icon.jsx'
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let name = this.props.name;
|
||||
const name = this.props.name;
|
||||
|
||||
if (name && name in codes) {
|
||||
let code = format.hexToDec(codes[name]);
|
||||
const code = format.hexToDec(codes[name]);
|
||||
return (
|
||||
<span
|
||||
className={`icon ${name}`}
|
||||
|
@ -43,4 +47,4 @@ export default React.createClass({
|
|||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,15 +2,19 @@ import React from 'react';
|
|||
|
||||
import App from '../App.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
export default class Link extends React.Component {
|
||||
|
||||
displayName: 'Link.jsx',
|
||||
displayName: 'Link.jsx'
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
// Navigate to a route.
|
||||
_navigate(link, evt) {
|
||||
App.navigate(link);
|
||||
evt.preventDefault();
|
||||
},
|
||||
}
|
||||
|
||||
render() {
|
||||
let route = this.props.route;
|
||||
|
@ -27,4 +31,4 @@ export default React.createClass({
|
|||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,14 +9,18 @@ import actions from '../actions/appActions.js';
|
|||
import Icon from './Icon.jsx';
|
||||
import Link from './Link.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
export default class Milestones extends React.Component {
|
||||
|
||||
displayName: 'Milestones.jsx',
|
||||
displayName: 'Milestones.jsx'
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
// Cycle through milestones sort order.
|
||||
_onSort() {
|
||||
actions.emit('projects.sort');
|
||||
},
|
||||
}
|
||||
|
||||
render() {
|
||||
let { projects, project } = this.props;
|
||||
|
@ -119,4 +123,4 @@ export default React.createClass({
|
|||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,17 +5,14 @@ import actions from '../actions/appActions.js';
|
|||
|
||||
import Icon from './Icon.jsx';
|
||||
|
||||
let Notify = React.createClass({
|
||||
class Notify extends React.Component {
|
||||
|
||||
displayName: 'Notify.jsx',
|
||||
displayName: 'Notify.jsx'
|
||||
|
||||
// Close notification.
|
||||
_onClose() {
|
||||
actions.emit('system.notify');
|
||||
},
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
this.props = {
|
||||
// No text.
|
||||
'text': null,
|
||||
// Grey style.
|
||||
|
@ -25,7 +22,12 @@ let Notify = React.createClass({
|
|||
// Just announcing.
|
||||
'icon': 'megaphone'
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
// Close notification.
|
||||
_onClose() {
|
||||
actions.emit('system.notify');
|
||||
}
|
||||
|
||||
render() {
|
||||
let { text, system, type, icon, ttl } = this.props;
|
||||
|
@ -51,9 +53,9 @@ let Notify = React.createClass({
|
|||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
export default React.createClass({
|
||||
export default class NotifyWrapper extends React.Component {
|
||||
|
||||
// TODO: animate in
|
||||
render() {
|
||||
|
@ -73,4 +75,4 @@ export default React.createClass({
|
|||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
import React from 'react';
|
||||
|
||||
// Inserts a space before rendering text.
|
||||
export default React.createClass({
|
||||
export default class Space extends React.Component {
|
||||
|
||||
displayName: 'Space.jsx',
|
||||
displayName: 'Space.jsx'
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return <span> </span>;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,18 +2,20 @@ import React from 'react';
|
|||
|
||||
import actions from '../../actions/appActions.js';
|
||||
|
||||
import Page from '../../lib/PageMixin.js';
|
||||
import Page from '../../lib/PageClass.js';
|
||||
|
||||
import Notify from '../Notify.jsx';
|
||||
import Header from '../Header.jsx';
|
||||
import Footer from '../Footer.jsx';
|
||||
import AddProjectForm from '../AddProjectForm.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
export default class AddProjectPage extends Page {
|
||||
|
||||
displayName: 'AddProjectPage.jsx',
|
||||
displayName: 'AddProjectPage.jsx'
|
||||
|
||||
mixins: [ Page ],
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
|
@ -35,4 +37,4 @@ export default React.createClass({
|
|||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
import Page from '../../lib/PageMixin.js';
|
||||
import Page from '../../lib/PageClass.js';
|
||||
|
||||
import format from '../../modules/format.js';
|
||||
|
||||
|
@ -10,11 +10,13 @@ import Header from '../Header.jsx';
|
|||
import Footer from '../Footer.jsx';
|
||||
import Chart from '../Chart.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
export default class ChartPage extends Page {
|
||||
|
||||
displayName: 'ChartPage.jsx',
|
||||
displayName: 'ChartPage.jsx'
|
||||
|
||||
mixins: [ Page ],
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let content;
|
||||
|
@ -70,4 +72,4 @@ export default React.createClass({
|
|||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
import Page from '../../lib/PageMixin.js';
|
||||
import Page from '../../lib/PageClass.js';
|
||||
|
||||
import Notify from '../Notify.jsx';
|
||||
import Header from '../Header.jsx';
|
||||
|
@ -9,17 +9,18 @@ import Footer from '../Footer.jsx';
|
|||
import Milestones from '../Milestones.jsx';
|
||||
import Chart from '../Chart.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
export default class MilestonePage extends Page {
|
||||
|
||||
displayName: 'MilestonesPage.jsx',
|
||||
displayName: 'MilestonesPage.jsx'
|
||||
|
||||
mixins: [ Page ],
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let content;
|
||||
if (!this.state.app.system.loading) {
|
||||
let projects = this.state.projects;
|
||||
|
||||
// Create the all milestones payload.
|
||||
let data;
|
||||
_.find(projects.list, (obj) => {
|
||||
|
@ -83,4 +84,4 @@ export default React.createClass({
|
|||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
import React from 'react';
|
||||
|
||||
import Page from '../../lib/PageMixin.js';
|
||||
import Page from '../../lib/PageClass.js';
|
||||
|
||||
// TODO: implement
|
||||
export default React.createClass({
|
||||
export default class NotFoundPage extends Page {
|
||||
|
||||
displayName: 'NotFoundPage.jsx',
|
||||
displayName: 'NotFoundPage.jsx'
|
||||
|
||||
mixins: [ Page ],
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div>Page {this.props.path} not found</div>;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
import Page from '../../lib/PageMixin.js';
|
||||
import Page from '../../lib/PageClass.js';
|
||||
|
||||
import Notify from '../Notify.jsx';
|
||||
import Header from '../Header.jsx';
|
||||
|
@ -9,23 +10,23 @@ import Milestones from '../Milestones.jsx';
|
|||
import EditProjects from '../EditProjects.jsx';
|
||||
import Hero from '../Hero.jsx';
|
||||
|
||||
export default React.createClass({
|
||||
export default class ProjectsPage extends Page {
|
||||
|
||||
displayName: 'ProjectsPage.jsx',
|
||||
displayName: 'ProjectsPage.jsx'
|
||||
|
||||
mixins: [ Page ],
|
||||
constructor(props) {
|
||||
super(props);
|
||||
// Start the page in a view mode.
|
||||
// NOTE probably move into its own component so we don't merge state.
|
||||
_.merge(this.state, { 'edit': false });
|
||||
// Bindings.
|
||||
this._onToggleMode = this._onToggleMode.bind(this);
|
||||
}
|
||||
|
||||
// Toggle between edit and view mode.
|
||||
_onToggleMode() {
|
||||
this.setState({ 'edit': !this.state.edit });
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
// Start the page in a view mode.
|
||||
'edit': false
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
render() {
|
||||
let content;
|
||||
|
@ -66,4 +67,4 @@ export default React.createClass({
|
|||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -21,12 +21,12 @@ export default class EventEmitter {
|
|||
// Add a listener on this path/regex.
|
||||
on(path, cb) {
|
||||
if (!_.isRegExp(path)) path = new RegExp(`^${path}$`);
|
||||
this.list.push({ pattern: path, cb: cb });
|
||||
this.list.push({ 'pattern': path, cb: cb });
|
||||
}
|
||||
|
||||
// Add a listener to all events.
|
||||
onAny(cb) {
|
||||
this.list.push({ pattern: /./, cb: cb });
|
||||
this.list.push({ 'pattern': /./, cb: cb });
|
||||
}
|
||||
|
||||
// Assume we can have multiple.
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
import stores from '../stores';
|
||||
|
||||
export default class Page extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
// State contains our store data.
|
||||
// NOTE top-level page components shouldn't modify the state.
|
||||
this.state = this._getData();
|
||||
// Bindings.
|
||||
this._onChange = this._onChange.bind(this);
|
||||
}
|
||||
|
||||
// Get the POJO of the store.
|
||||
_getData(store) {
|
||||
let obj = {};
|
||||
if (store) {
|
||||
obj[store] = stores[store].get();
|
||||
} else {
|
||||
// Get all stores.
|
||||
for (let key in stores) {
|
||||
obj[key] = stores[key].get();
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Update the state when store changes.
|
||||
_onChange(store, val, key) {
|
||||
if (!this._isMounted) return;
|
||||
this.setState(this._getData(store));
|
||||
}
|
||||
|
||||
// Listen to all events (data changes).
|
||||
componentDidMount() {
|
||||
this._isMounted = true;
|
||||
|
||||
for (let key in stores) {
|
||||
stores[key].onAny(_.partial(this._onChange, key));
|
||||
}
|
||||
}
|
||||
|
||||
// Stop listening to store changes.
|
||||
componentWillUnmount() {
|
||||
this._isMounted = false;
|
||||
|
||||
for (let key in stores) {
|
||||
stores[key].clean(this._onChange);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
import stores from '../stores';
|
||||
|
||||
export default {
|
||||
|
||||
// Get the POJO of the store.
|
||||
_getData(store) {
|
||||
let obj = {};
|
||||
if (store) {
|
||||
obj[store] = stores[store].get();
|
||||
} else {
|
||||
// Get all stores.
|
||||
let key;
|
||||
for (key in stores) {
|
||||
obj[key] = stores[key].get();
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
},
|
||||
|
||||
_onChange(store, val, key) {
|
||||
if (this.isMounted()) { // not ideal
|
||||
this.setState(this._getData(store));
|
||||
}
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return this._getData();
|
||||
},
|
||||
|
||||
// Listen to all events (data changes).
|
||||
componentDidMount() {
|
||||
let key;
|
||||
for (key in stores) {
|
||||
stores[key].onAny(_.partial(this._onChange, key));
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
let key;
|
||||
for (key in stores) {
|
||||
stores[key].clean(this._onChange);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
|
@ -73,7 +73,7 @@
|
|||
}
|
||||
|
||||
&.action {
|
||||
background: darken(@strong_color, 15%);
|
||||
color: darken(@strong_color, 15%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue