Move to CSS modules
Also includes misc fixes * Use CSS modules for all the CSS. * Fix a bug in the filterbar which was not filtering anything. * Fix a l10n issue in songs view. * Update hook to clean build repo before running, preventing to push dev built code. * Update webpack build code.
This commit is contained in:
förälder
921028c073
incheckning
2d9747482b
|
@ -0,0 +1,116 @@
|
|||
---
|
||||
# Output debugging info
|
||||
loglevel: disabled
|
||||
|
||||
# Major version of Bootstrap: 3 or 4
|
||||
bootstrapVersion: 3
|
||||
|
||||
# If Bootstrap version 3 is used - turn on/off custom icon font path
|
||||
useCustomIconFontPath: false
|
||||
|
||||
# Webpack loaders, order matters
|
||||
styleLoaders:
|
||||
- style
|
||||
- css
|
||||
- sass
|
||||
|
||||
# Extract styles to stand-alone css file
|
||||
# Different settings for different environments can be used,
|
||||
# It depends on value of NODE_ENV environment variable
|
||||
# This param can also be set in webpack config:
|
||||
# entry: 'bootstrap-loader/extractStyles'
|
||||
extractStyles: true
|
||||
# env:
|
||||
# development:
|
||||
# extractStyles: false
|
||||
# production:
|
||||
# extractStyles: true
|
||||
|
||||
|
||||
# Customize Bootstrap variables that get imported before the original Bootstrap variables.
|
||||
# Thus, derived Bootstrap variables can depend on values from here.
|
||||
# See the Bootstrap _variables.scss file for examples of derived Bootstrap variables.
|
||||
#
|
||||
# preBootstrapCustomizations: ./path/to/bootstrap/pre-customizations.scss
|
||||
|
||||
|
||||
# This gets loaded after bootstrap/variables is loaded
|
||||
# Thus, you may customize Bootstrap variables
|
||||
# based on the values established in the Bootstrap _variables.scss file
|
||||
#
|
||||
# bootstrapCustomizations: ./path/to/bootstrap/customizations.scss
|
||||
|
||||
|
||||
# Import your custom styles here
|
||||
# Usually this endpoint-file contains list of @imports of your application styles
|
||||
#
|
||||
# appStyles: ./path/to/your/app/styles/endpoint.scss
|
||||
|
||||
|
||||
### Bootstrap styles
|
||||
styles:
|
||||
|
||||
# Mixins
|
||||
mixins: true
|
||||
|
||||
# Reset and dependencies
|
||||
normalize: true
|
||||
print: true
|
||||
glyphicons: true
|
||||
|
||||
# Core CSS
|
||||
scaffolding: true
|
||||
type: true
|
||||
code: true
|
||||
grid: true
|
||||
tables: true
|
||||
forms: true
|
||||
buttons: true
|
||||
|
||||
# Components
|
||||
component-animations: true
|
||||
dropdowns: true
|
||||
button-groups: true
|
||||
input-groups: true
|
||||
navs: true
|
||||
navbar: true
|
||||
breadcrumbs: true
|
||||
pagination: true
|
||||
pager: true
|
||||
labels: true
|
||||
badges: true
|
||||
jumbotron: true
|
||||
thumbnails: true
|
||||
alerts: true
|
||||
progress-bars: true
|
||||
media: true
|
||||
list-group: true
|
||||
panels: true
|
||||
wells: true
|
||||
responsive-embed: true
|
||||
close: true
|
||||
|
||||
# Components w/ JavaScript
|
||||
modals: true
|
||||
tooltip: true
|
||||
popovers: true
|
||||
carousel: true
|
||||
|
||||
# Utility classes
|
||||
utilities: true
|
||||
responsive-utilities: true
|
||||
|
||||
### Bootstrap scripts
|
||||
scripts:
|
||||
transition: true
|
||||
alert: true
|
||||
button: true
|
||||
carousel: true
|
||||
collapse: true
|
||||
dropdown: true
|
||||
modal: true
|
||||
tooltip: true
|
||||
popover: true
|
||||
scrollspy: true
|
||||
tab: true
|
||||
affix: true
|
|
@ -21,13 +21,13 @@ A few `npm` scripts are provided:
|
|||
|
||||
Translations are handled by [react-intl](https://github.com/yahoo/react-intl/).
|
||||
|
||||
`npm run extractTranslations` output a file containing all the english
|
||||
`npm run --silent extractTranslations` output a file containing all the english
|
||||
translations, in the expected form. It is a mapping of ids and strings to
|
||||
translate, with an extra description provided as a comment at the end of the
|
||||
line, for some translation context.
|
||||
|
||||
Typically, if you want to translate to another `$LOCALE` (say `fr-FR`), create
|
||||
a folder `./app/locales/$LOCALE`, put inside the generated file from `npm run
|
||||
extractTranslations`, called `index.js`. Copy the lines in
|
||||
--silent extractTranslations`, called `index.js`. Copy the lines in
|
||||
`./app/locales/index.js` to include your new translation and translate all the
|
||||
strings in the `./app/locales/$LOCALE/index.js` file you have just created.
|
||||
|
|
7
TODO
7
TODO
|
@ -5,12 +5,8 @@
|
|||
8. Search
|
||||
9. Discover
|
||||
|
||||
|
||||
# CSS
|
||||
* Sidebar responsiveness
|
||||
* Move CSS in modules
|
||||
=> https://github.com/gajus/react-css-modules
|
||||
|
||||
* Focus stays on navbar
|
||||
|
||||
# API middleware
|
||||
* https://github.com/reactjs/redux/issues/1824#issuecomment-228609501
|
||||
|
@ -18,6 +14,7 @@
|
|||
* https://github.com/reactjs/redux/issues/644
|
||||
* https://github.com/peterpme/redux-crud-api-middleware/blob/master/README.md
|
||||
* https://github.com/madou/armory-front/tree/master/src/app/reducers
|
||||
* https://github.com/erikras/multireducer
|
||||
* Immutable.js (?) + get rid of lodash
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import React, { Component, PropTypes } from "react";
|
||||
import CSSModules from "react-css-modules";
|
||||
|
||||
import { formatLength } from "../utils";
|
||||
|
||||
import css from "../styles/Album.scss";
|
||||
|
||||
export class AlbumTrackRow extends Component {
|
||||
render () {
|
||||
const length = formatLength(this.props.track.length);
|
||||
|
@ -40,28 +43,34 @@ AlbumTracksTable.propTypes = {
|
|||
tracks: PropTypes.array.isRequired
|
||||
};
|
||||
|
||||
export class AlbumRow extends Component {
|
||||
class AlbumRowCSS extends Component {
|
||||
render () {
|
||||
return (
|
||||
<div className="row albumRow">
|
||||
<div className="col-sm-offset-2 col-xs-10 albumRowName">
|
||||
<div className="row" styleName="row">
|
||||
<div className="col-sm-offset-2 col-xs-10" styleName="nameRow">
|
||||
<h2>{this.props.album.name}</h2>
|
||||
</div>
|
||||
<div className="col-xs-2 albumRowArt">
|
||||
<p className="text-center"><img src={this.props.album.art} width="200" height="200" className="img-responsive img-circle art" alt={this.props.album.name} /></p>
|
||||
<div className="col-xs-2" styleName="artRow">
|
||||
<p className="text-center"><img src={this.props.album.art} width="200" height="200" className="img-responsive img-circle" styleName="art" alt={this.props.album.name} /></p>
|
||||
</div>
|
||||
<div className="col-sm-10 table-responsive">
|
||||
<AlbumTracksTable tracks={this.props.album.tracks} />
|
||||
{
|
||||
Array.isArray(this.props.album.tracks) ?
|
||||
<AlbumTracksTable tracks={this.props.album.tracks} /> :
|
||||
null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AlbumRow.propTypes = {
|
||||
AlbumRowCSS.propTypes = {
|
||||
album: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export let AlbumRow = CSSModules(AlbumRowCSS, css);
|
||||
|
||||
export default class Album extends Component {
|
||||
render () {
|
||||
return (
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import React, { Component, PropTypes } from "react";
|
||||
import CSSModules from "react-css-modules";
|
||||
|
||||
import { AlbumRow } from "./Album";
|
||||
|
||||
export default class Artist extends Component {
|
||||
import css from "../styles/Artist.scss";
|
||||
|
||||
class ArtistCSS extends Component {
|
||||
render () {
|
||||
var albumsRows = [];
|
||||
if (Array.isArray(this.props.artist.albums)) {
|
||||
|
@ -12,7 +15,7 @@ export default class Artist extends Component {
|
|||
}
|
||||
return (
|
||||
<div>
|
||||
<div className="row artistNameRow">
|
||||
<div className="row" styleName="name">
|
||||
<div className="col-sm-12">
|
||||
<h1>{this.props.artist.name}</h1>
|
||||
<hr/>
|
||||
|
@ -23,7 +26,7 @@ export default class Artist extends Component {
|
|||
<p>{this.props.artist.summary}</p>
|
||||
</div>
|
||||
<div className="col-sm-3 text-center">
|
||||
<p><img src={this.props.artist.art} width="200" height="200" className="img-responsive img-circle art" alt={this.props.artist.name}/></p>
|
||||
<p><img src={this.props.artist.art} width="200" height="200" className="img-responsive img-circle" styleName="art" alt={this.props.artist.name}/></p>
|
||||
</div>
|
||||
</div>
|
||||
{ albumsRows }
|
||||
|
@ -32,6 +35,8 @@ export default class Artist extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
Artist.propTypes = {
|
||||
ArtistCSS.propTypes = {
|
||||
artist: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default CSSModules(ArtistCSS, css);
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
import React, { Component, PropTypes } from "react";
|
||||
import CSSModules from "react-css-modules";
|
||||
import { defineMessages, injectIntl, intlShape, FormattedMessage } from "react-intl";
|
||||
|
||||
import { messagesMap } from "../utils";
|
||||
import messages from "../locales/messagesDescriptors/Login";
|
||||
|
||||
import css from "../styles/Login.scss";
|
||||
|
||||
const loginMessages = defineMessages(messagesMap(messages));
|
||||
|
||||
class LoginFormIntl extends Component {
|
||||
class LoginFormCSSIntl extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
|
@ -61,8 +64,8 @@ class LoginFormIntl extends Component {
|
|||
{
|
||||
this.props.error ?
|
||||
<div className="row">
|
||||
<div className="alert alert-danger">
|
||||
<p id="loginFormError">
|
||||
<div className="alert alert-danger" id="loginFormError">
|
||||
<p>
|
||||
<span className="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> { this.props.error }
|
||||
</p>
|
||||
</div>
|
||||
|
@ -105,7 +108,7 @@ class LoginFormIntl extends Component {
|
|||
<FormattedMessage {...loginMessages["app.login.rememberMe"]} />
|
||||
</label>
|
||||
</div>
|
||||
<div className="col-sm-6 col-sm-12 submit text-right">
|
||||
<div className="col-sm-6 col-xs-12 text-right" styleName="submit">
|
||||
<input type="submit" className="btn btn-default" aria-label={formatMessage(loginMessages["app.login.signIn"])} defaultValue={formatMessage(loginMessages["app.login.signIn"])} disabled={this.props.isAuthenticating} />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -119,7 +122,7 @@ class LoginFormIntl extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
LoginFormIntl.propTypes = {
|
||||
LoginFormCSSIntl.propTypes = {
|
||||
username: PropTypes.string,
|
||||
endpoint: PropTypes.string,
|
||||
rememberMe: PropTypes.bool,
|
||||
|
@ -130,10 +133,10 @@ LoginFormIntl.propTypes = {
|
|||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export let LoginForm = injectIntl(LoginFormIntl);
|
||||
export let LoginForm = injectIntl(CSSModules(LoginFormCSSIntl, css));
|
||||
|
||||
|
||||
export default class Login extends Component {
|
||||
class Login extends Component {
|
||||
render () {
|
||||
const greeting = (
|
||||
<p>
|
||||
|
@ -141,8 +144,8 @@ export default class Login extends Component {
|
|||
</p>
|
||||
);
|
||||
return (
|
||||
<div className="login text-center container-fluid">
|
||||
<h1><img src="./app/assets/img/ampache-blue.png" alt="A"/>mpache</h1>
|
||||
<div className="text-center container-fluid">
|
||||
<h1><img styleName="titleImage" src="./app/assets/img/ampache-blue.png" alt="A"/>mpache</h1>
|
||||
<hr/>
|
||||
{(!this.props.error && !this.props.info) ? greeting : null}
|
||||
<div className="col-sm-9 col-sm-offset-2 col-md-6 col-md-offset-3">
|
||||
|
@ -162,3 +165,5 @@ Login.propTypes = {
|
|||
error: PropTypes.string,
|
||||
info: PropTypes.string
|
||||
};
|
||||
|
||||
export default CSSModules(Login, css);
|
||||
|
|
|
@ -65,13 +65,13 @@ export class SongsTable extends Component {
|
|||
<FormattedMessage {...songsMessages["app.songs.title"]} />
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage {...songsMessages["app.common.artist"]} />
|
||||
<FormattedMessage {...songsMessages["app.common.artist"]} values={{itemCount: 1}} />
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage {...songsMessages["app.common.album"]} />
|
||||
<FormattedMessage {...songsMessages["app.common.album"]} values={{itemCount: 1}} />
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage {...songsMessages["app.common.genre"]} />
|
||||
<FormattedMessage {...songsMessages["app.songs.genre"]} />
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage {...songsMessages["app.songs.length"]} />
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
import React, { Component, PropTypes } from "react";
|
||||
import CSSModules from "react-css-modules";
|
||||
import { defineMessages, injectIntl, intlShape, FormattedMessage } from "react-intl";
|
||||
|
||||
import { messagesMap } from "../../utils";
|
||||
import messages from "../../locales/messagesDescriptors/elements/FilterBar";
|
||||
|
||||
import css from "../../styles/elements/FilterBar.scss";
|
||||
|
||||
const filterMessages = defineMessages(messagesMap(messages));
|
||||
|
||||
class FilterBarIntl extends Component {
|
||||
class FilterBarCSSIntl extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
|
@ -21,14 +24,14 @@ class FilterBarIntl extends Component {
|
|||
render () {
|
||||
const {formatMessage} = this.props.intl;
|
||||
return (
|
||||
<div className="filter">
|
||||
<p className="col-xs-12 col-sm-6 col-md-4 col-md-offset-1 filter-legend" id="filterInputDescription">
|
||||
<div styleName="filter">
|
||||
<p className="col-xs-12 col-sm-6 col-md-4 col-md-offset-1" styleName="legend" id="filterInputDescription">
|
||||
<FormattedMessage {...filterMessages["app.filter.whatAreWeListeningToToday"]} />
|
||||
</p>
|
||||
<div className="col-xs-12 col-sm-6 col-md-4 input-group">
|
||||
<form className="form-inline" onSubmit={this.handleChange} aria-describedby="filterInputDescription">
|
||||
<div className="form-group">
|
||||
<input type="text" className="form-control filter-input" placeholder={formatMessage(filterMessages["app.filter.filter"])} aria-label={formatMessage(filterMessages["app.filter.filter"])} value={this.props.filterText} onChange={this.handleChange} ref="filterTextInput" />
|
||||
<div className="form-group" styleName="form-group">
|
||||
<input type="text" className="form-control" placeholder={formatMessage(filterMessages["app.filter.filter"])} aria-label={formatMessage(filterMessages["app.filter.filter"])} value={this.props.filterText} onChange={this.handleChange} ref="filterTextInput" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -37,11 +40,10 @@ class FilterBarIntl extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
FilterBarIntl.propTypes = {
|
||||
FilterBarCSSIntl.propTypes = {
|
||||
onUserInput: PropTypes.func,
|
||||
filterText: PropTypes.string,
|
||||
intl: intlShape.isRequired
|
||||
};
|
||||
|
||||
export let FilterBar = injectIntl(FilterBarIntl);
|
||||
export default FilterBar;
|
||||
export default injectIntl(CSSModules(FilterBarCSSIntl, css));
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, { Component, PropTypes } from "react";
|
||||
import { Link} from "react-router";
|
||||
import CSSModules from "react-css-modules";
|
||||
import imagesLoaded from "imagesloaded";
|
||||
import Isotope from "isotope-layout";
|
||||
import Fuse from "fuse.js";
|
||||
|
@ -8,7 +9,9 @@ import _ from "lodash";
|
|||
import FilterBar from "./FilterBar";
|
||||
import Pagination from "./Pagination";
|
||||
|
||||
export class GridItem extends Component {
|
||||
import css from "../../styles/elements/Grid.scss";
|
||||
|
||||
class GridItemCSS extends Component {
|
||||
render () {
|
||||
var nSubItems = this.props.item[this.props.subItemsType];
|
||||
if (Array.isArray(nSubItems)) {
|
||||
|
@ -27,10 +30,10 @@ export class GridItem extends Component {
|
|||
// TODO: i18n
|
||||
const title = "Go to " + this.props.itemsType.rstrip("s") + " page";
|
||||
return (
|
||||
<div className="grid-item col-xs-6 col-sm-3 placeholders" id={id}>
|
||||
<div className="grid-item-content placeholder text-center">
|
||||
<Link title={title} to={to}><img src={this.props.item.art} width="200" height="200" className="img-responsive img-circle art" alt={this.props.item.name}/></Link>
|
||||
<h4 className="name">{this.props.item.name}</h4>
|
||||
<div className="grid-item col-xs-6 col-sm-3" styleName="placeholders" id={id}>
|
||||
<div className="grid-item-content text-center">
|
||||
<Link title={title} to={to}><img src={this.props.item.art} width="200" height="200" className="img-responsive img-circle art" styleName="art" alt={this.props.item.name}/></Link>
|
||||
<h4 className="name" styleName="name">{this.props.item.name}</h4>
|
||||
<span className="sub-items text-muted"><span className="n-sub-items">{nSubItems}</span> <span className="sub-items-type">{subItemsLabel}</span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -38,12 +41,14 @@ export class GridItem extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
GridItem.propTypes = {
|
||||
GridItemCSS.propTypes = {
|
||||
item: PropTypes.object.isRequired,
|
||||
itemsType: PropTypes.string.isRequired,
|
||||
subItemsType: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export let GridItem = CSSModules(GridItemCSS, css);
|
||||
|
||||
|
||||
const ISOTOPE_OPTIONS = { /** Default options for Isotope grid layout. */
|
||||
getSortData: {
|
||||
|
@ -93,9 +98,9 @@ export class Grid extends Component {
|
|||
|
||||
// Apply filter on grid
|
||||
this.iso.arrange({
|
||||
filter: function () {
|
||||
var name = $(this).find(".name").text();
|
||||
return result.find(function (item) { return item.item.name == name; });
|
||||
filter: function (item) {
|
||||
var name = $(item).find(".name").text();
|
||||
return result.find(function (i) { return i.item.name == name; });
|
||||
},
|
||||
transitionDuration: "0.4s",
|
||||
getSortData: {
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
import React, { Component, PropTypes } from "react";
|
||||
import { Link, withRouter } from "react-router";
|
||||
import CSSModules from "react-css-modules";
|
||||
import { defineMessages, injectIntl, intlShape, FormattedMessage, FormattedHTMLMessage } from "react-intl";
|
||||
|
||||
import { messagesMap } from "../../utils";
|
||||
import commonMessages from "../../locales/messagesDescriptors/common";
|
||||
import messages from "../../locales/messagesDescriptors/elements/Pagination";
|
||||
|
||||
import css from "../../styles/elements/Pagination.scss";
|
||||
|
||||
const paginationMessages = defineMessages(messagesMap(Array.concat([], commonMessages, messages)));
|
||||
|
||||
export class PaginationIntl extends Component {
|
||||
class PaginationCSSIntl extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.buildLinkTo.bind(this);
|
||||
|
@ -134,8 +137,8 @@ export class PaginationIntl extends Component {
|
|||
if (pagesButton.length > 1) {
|
||||
return (
|
||||
<div>
|
||||
<nav className="pagination-nav" aria-label={formatMessage(paginationMessages["app.pagination.pageNavigation"])}>
|
||||
<ul className="pagination">
|
||||
<nav className="pagination-nav" styleName="nav" aria-label={formatMessage(paginationMessages["app.pagination.pageNavigation"])}>
|
||||
<ul className="pagination" styleName="pointer">
|
||||
{ pagesButton }
|
||||
</ul>
|
||||
</nav>
|
||||
|
@ -171,12 +174,11 @@ export class PaginationIntl extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
PaginationIntl.propTypes = {
|
||||
PaginationCSSIntl.propTypes = {
|
||||
currentPage: PropTypes.number.isRequired,
|
||||
location: PropTypes.object.isRequired,
|
||||
nPages: PropTypes.number.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export let Pagination = withRouter(injectIntl(PaginationIntl));
|
||||
export default Pagination;
|
||||
export default withRouter(injectIntl(CSSModules(PaginationCSSIntl, css)));
|
||||
|
|
|
@ -1,39 +1,42 @@
|
|||
import React, { Component, PropTypes } from "react";
|
||||
import { IndexLink, Link} from "react-router";
|
||||
import CSSModules from "react-css-modules";
|
||||
import { defineMessages, injectIntl, intlShape, FormattedMessage } from "react-intl";
|
||||
|
||||
import { messagesMap } from "../../utils";
|
||||
import commonMessages from "../../locales/messagesDescriptors/common";
|
||||
import messages from "../../locales/messagesDescriptors/layouts/Sidebar";
|
||||
|
||||
import css from "../../styles/layouts/Sidebar.scss";
|
||||
|
||||
const sidebarLayoutMessages = defineMessages(messagesMap(Array.concat([], commonMessages, messages)));
|
||||
|
||||
export default class SidebarLayoutIntl extends Component {
|
||||
class SidebarLayoutIntl extends Component {
|
||||
render () {
|
||||
const { formatMessage } = this.props.intl;
|
||||
const isActive = {
|
||||
discover: (this.props.location.pathname == "/discover") ? "active" : "",
|
||||
browse: (this.props.location.pathname == "/browse") ? "active" : "",
|
||||
artists: (this.props.location.pathname == "/artists") ? "active" : "",
|
||||
albums: (this.props.location.pathname == "/albums") ? "active" : "",
|
||||
songs: (this.props.location.pathname == "/songs") ? "active" : "",
|
||||
search: (this.props.location.pathname == "/search") ? "active" : ""
|
||||
discover: (this.props.location.pathname == "/discover") ? "active" : "link",
|
||||
browse: (this.props.location.pathname == "/browse") ? "active" : "link",
|
||||
artists: (this.props.location.pathname == "/artists") ? "active" : "link",
|
||||
albums: (this.props.location.pathname == "/albums") ? "active" : "link",
|
||||
songs: (this.props.location.pathname == "/songs") ? "active" : "link",
|
||||
search: (this.props.location.pathname == "/search") ? "active" : "link"
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<div className="col-sm-1 col-md-2 sidebar hidden-xs">
|
||||
<h1 className="text-center">
|
||||
<IndexLink to="/">
|
||||
<img alt="A" src="./app/assets/img/ampache-blue.png"/>
|
||||
<div className="col-sm-1 col-md-2 hidden-xs" styleName="sidebar">
|
||||
<h1 className="text-center" styleName="title">
|
||||
<IndexLink to="/" styleName="link">
|
||||
<img alt="A" src="./app/assets/img/ampache-blue.png" styleName="imgTitle" />
|
||||
<span className="hidden-sm">mpache</span>
|
||||
</IndexLink>
|
||||
</h1>
|
||||
<nav aria-label={formatMessage(sidebarLayoutMessages["app.sidebarLayout.mainNavigationMenu"])}>
|
||||
<div className="navbar text-center icon-navbar">
|
||||
<div className="navbar text-center" styleName="icon-navbar">
|
||||
<div className="container-fluid">
|
||||
<ul className="nav navbar-nav icon-navbar-nav">
|
||||
<ul className="nav navbar-nav" styleName="nav">
|
||||
<li>
|
||||
<Link to="/" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.home"])}>
|
||||
<Link to="/" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.home"])} styleName="link">
|
||||
<span className="glyphicon glyphicon-home" aria-hidden="true"></span>
|
||||
<span className="sr-only">
|
||||
<FormattedMessage {...sidebarLayoutMessages["app.sidebarLayout.home"]} />
|
||||
|
@ -41,7 +44,7 @@ export default class SidebarLayoutIntl extends Component {
|
|||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/settings" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.settings"])}>
|
||||
<Link to="/settings" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.settings"])} styleName="link">
|
||||
<span className="glyphicon glyphicon-wrench" aria-hidden="true"></span>
|
||||
<span className="sr-only">
|
||||
<FormattedMessage {...sidebarLayoutMessages["app.sidebarLayout.settings"]} />
|
||||
|
@ -49,7 +52,7 @@ export default class SidebarLayoutIntl extends Component {
|
|||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/logout" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.logout"])}>
|
||||
<Link to="/logout" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.logout"])} styleName="link">
|
||||
<span className="glyphicon glyphicon-off" aria-hidden="true"></span>
|
||||
<span className="sr-only">
|
||||
<FormattedMessage {...sidebarLayoutMessages["app.sidebarLayout.logout"]} />
|
||||
|
@ -59,9 +62,9 @@ export default class SidebarLayoutIntl extends Component {
|
|||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="nav nav-sidebar">
|
||||
<ul className="nav" styleName="nav">
|
||||
<li>
|
||||
<Link to="/discover" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.discover"])} className={isActive.discover}>
|
||||
<Link to="/discover" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.discover"])} styleName={isActive.discover}>
|
||||
<span className="glyphicon glyphicon-globe" aria-hidden="true"></span>
|
||||
<span className="hidden-sm">
|
||||
<FormattedMessage {...sidebarLayoutMessages["app.sidebarLayout.discover"]} />
|
||||
|
@ -69,7 +72,7 @@ export default class SidebarLayoutIntl extends Component {
|
|||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/browse" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.browse"])} className={isActive.browse}>
|
||||
<Link to="/browse" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.browse"])} styleName={isActive.browse}>
|
||||
<span className="glyphicon glyphicon-headphones" aria-hidden="true"></span>
|
||||
<span className="hidden-sm">
|
||||
<FormattedMessage {...sidebarLayoutMessages["app.sidebarLayout.browse"]} />
|
||||
|
@ -77,7 +80,7 @@ export default class SidebarLayoutIntl extends Component {
|
|||
</Link>
|
||||
<ul className="nav nav-list text-center">
|
||||
<li>
|
||||
<Link to="/artists" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.browseArtists"])} className={isActive.artists}>
|
||||
<Link to="/artists" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.browseArtists"])} styleName={isActive.artists}>
|
||||
<span className="glyphicon glyphicon-user" aria-hidden="true"></span>
|
||||
<span className="sr-only">
|
||||
<FormattedMessage {...sidebarLayoutMessages["app.common.artist"]} values={{itemCount: 42}} />
|
||||
|
@ -88,7 +91,7 @@ export default class SidebarLayoutIntl extends Component {
|
|||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/albums" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.browseAlbums"])} className={isActive.albums}>
|
||||
<Link to="/albums" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.browseAlbums"])} styleName={isActive.albums}>
|
||||
<span className="glyphicon glyphicon-cd" aria-hidden="true"></span>
|
||||
<span className="sr-only"><FormattedMessage {...sidebarLayoutMessages["app.common.album"]} values={{itemCount: 42}} /></span>
|
||||
<span className="hidden-sm">
|
||||
|
@ -97,7 +100,7 @@ export default class SidebarLayoutIntl extends Component {
|
|||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/songs" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.browseSongs"])} className={isActive.songs}>
|
||||
<Link to="/songs" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.browseSongs"])} styleName={isActive.songs}>
|
||||
<span className="glyphicon glyphicon-music" aria-hidden="true"></span>
|
||||
<span className="sr-only">
|
||||
<FormattedMessage {...sidebarLayoutMessages["app.common.song"]} values={{itemCount: 42}} />
|
||||
|
@ -110,7 +113,7 @@ export default class SidebarLayoutIntl extends Component {
|
|||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/search" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.search"])} className={isActive.search}>
|
||||
<Link to="/search" title={formatMessage(sidebarLayoutMessages["app.sidebarLayout.search"])} styleName={isActive.search}>
|
||||
<span className="glyphicon glyphicon-search" aria-hidden="true"></span>
|
||||
<span className="hidden-sm">
|
||||
<FormattedMessage {...sidebarLayoutMessages["app.sidebarLayout.search"]} />
|
||||
|
@ -121,7 +124,7 @@ export default class SidebarLayoutIntl extends Component {
|
|||
</nav>
|
||||
</div>
|
||||
|
||||
<div className="col-sm-11 col-sm-offset-1 col-md-10 col-md-offset-2 main-panel">
|
||||
<div className="col-sm-11 col-sm-offset-1 col-md-10 col-md-offset-2" styleName="main-panel">
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -135,5 +138,4 @@ SidebarLayoutIntl.propTypes = {
|
|||
intl: intlShape.isRequired
|
||||
};
|
||||
|
||||
export let SidebarLayout = injectIntl(SidebarLayoutIntl);
|
||||
export default SidebarLayout;
|
||||
export default injectIntl(CSSModules(SidebarLayoutIntl, css));
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,2 +1,2 @@
|
|||
!function(e){function t(r){if(n[r])return n[r].exports;var a=n[r]={exports:{},id:r,loaded:!1};return e[r].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n={};return t.m=e,t.c=n,t.p="./",t(0)}({0:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(526);Object.keys(r).forEach(function(e){"default"!==e&&Object.defineProperty(t,e,{enumerable:!0,get:function(){return r[e]}})})},526:function(e,t){!function(t,n){function r(e,t){var n=e.createElement("p"),r=e.getElementsByTagName("head")[0]||e.documentElement;return n.innerHTML="x<style>"+t+"</style>",r.insertBefore(n.lastChild,r.firstChild)}function a(){var e=b.elements;return"string"==typeof e?e.split(" "):e}function o(e,t){var n=b.elements;"string"!=typeof n&&(n=n.join(" ")),"string"!=typeof e&&(e=e.join(" ")),b.elements=n+" "+e,s(t)}function c(e){var t=E[e[v]];return t||(t={},y++,e[v]=y,E[y]=t),t}function i(e,t,r){if(t||(t=n),f)return t.createElement(e);r||(r=c(t));var a;return a=r.cache[e]?r.cache[e].cloneNode():g.test(e)?(r.cache[e]=r.createElem(e)).cloneNode():r.createElem(e),!a.canHaveChildren||p.test(e)||a.tagUrn?a:r.frag.appendChild(a)}function l(e,t){if(e||(e=n),f)return e.createDocumentFragment();t=t||c(e);for(var r=t.frag.cloneNode(),o=0,i=a(),l=i.length;o<l;o++)r.createElement(i[o]);return r}function u(e,t){t.cache||(t.cache={},t.createElem=e.createElement,t.createFrag=e.createDocumentFragment,t.frag=t.createFrag()),e.createElement=function(n){return b.shivMethods?i(n,e,t):t.createElem(n)},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+a().join().replace(/[\w\-:]+/g,function(e){return t.createElem(e),t.frag.createElement(e),'c("'+e+'")'})+");return n}")(b,t.frag)}function s(e){e||(e=n);var t=c(e);return!b.shivCSS||d||t.hasCSS||(t.hasCSS=!!r(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),f||u(e,t),e}var d,f,m="3.7.3-pre",h=t.html5||{},p=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,g=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",y=0,E={};!function(){try{var e=n.createElement("a");e.innerHTML="<xyz></xyz>",d="hidden"in e,f=1==e.childNodes.length||function(){n.createElement("a");var e=n.createDocumentFragment();return"undefined"==typeof e.cloneNode||"undefined"==typeof e.createDocumentFragment||"undefined"==typeof e.createElement}()}catch(t){d=!0,f=!0}}();var b={elements:h.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:h.shivCSS!==!1,supportsUnknownElements:f,shivMethods:h.shivMethods!==!1,type:"default",shivDocument:s,createElement:i,createDocumentFragment:l,addElements:o};t.html5=b,s(n),"object"==typeof e&&e.exports&&(e.exports=b)}("undefined"!=typeof window?window:this,document)}});
|
||||
!function(e){function t(r){if(n[r])return n[r].exports;var a=n[r]={exports:{},id:r,loaded:!1};return e[r].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n={};return t.m=e,t.c=n,t.p="./",t(0)}({0:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(585);Object.keys(r).forEach(function(e){"default"!==e&&Object.defineProperty(t,e,{enumerable:!0,get:function(){return r[e]}})})},585:function(e,t){!function(t,n){function r(e,t){var n=e.createElement("p"),r=e.getElementsByTagName("head")[0]||e.documentElement;return n.innerHTML="x<style>"+t+"</style>",r.insertBefore(n.lastChild,r.firstChild)}function a(){var e=b.elements;return"string"==typeof e?e.split(" "):e}function o(e,t){var n=b.elements;"string"!=typeof n&&(n=n.join(" ")),"string"!=typeof e&&(e=e.join(" ")),b.elements=n+" "+e,s(t)}function c(e){var t=E[e[v]];return t||(t={},y++,e[v]=y,E[y]=t),t}function i(e,t,r){if(t||(t=n),f)return t.createElement(e);r||(r=c(t));var a;return a=r.cache[e]?r.cache[e].cloneNode():g.test(e)?(r.cache[e]=r.createElem(e)).cloneNode():r.createElem(e),!a.canHaveChildren||p.test(e)||a.tagUrn?a:r.frag.appendChild(a)}function l(e,t){if(e||(e=n),f)return e.createDocumentFragment();t=t||c(e);for(var r=t.frag.cloneNode(),o=0,i=a(),l=i.length;o<l;o++)r.createElement(i[o]);return r}function u(e,t){t.cache||(t.cache={},t.createElem=e.createElement,t.createFrag=e.createDocumentFragment,t.frag=t.createFrag()),e.createElement=function(n){return b.shivMethods?i(n,e,t):t.createElem(n)},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+a().join().replace(/[\w\-:]+/g,function(e){return t.createElem(e),t.frag.createElement(e),'c("'+e+'")'})+");return n}")(b,t.frag)}function s(e){e||(e=n);var t=c(e);return!b.shivCSS||d||t.hasCSS||(t.hasCSS=!!r(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),f||u(e,t),e}var d,f,m="3.7.3-pre",h=t.html5||{},p=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,g=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",y=0,E={};!function(){try{var e=n.createElement("a");e.innerHTML="<xyz></xyz>",d="hidden"in e,f=1==e.childNodes.length||function(){n.createElement("a");var e=n.createDocumentFragment();return"undefined"==typeof e.cloneNode||"undefined"==typeof e.createDocumentFragment||"undefined"==typeof e.createElement}()}catch(t){d=!0,f=!0}}();var b={elements:h.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:h.shivCSS!==!1,supportsUnknownElements:f,shivMethods:h.shivMethods!==!1,type:"default",shivDocument:s,createElement:i,createDocumentFragment:l,addElements:o};t.html5=b,s(n),"object"==typeof e&&e.exports&&(e.exports=b)}("undefined"!=typeof window?window:this,document)}});
|
||||
//# sourceMappingURL=fix.ie9.js.map
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
|||
[]
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,27 @@
|
|||
.row {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.art {
|
||||
composes: art from "./elements/Grid.scss";
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.nameRow h2 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.artRow p,
|
||||
.artRow img {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nameRow,
|
||||
.artRow {
|
||||
float: none;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
.name > h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.name > hr {
|
||||
margin-top: 0.5em; /* Default value. */
|
||||
}
|
||||
|
||||
.art {
|
||||
composes: art from "./elements/Grid.scss";
|
||||
}
|
||||
|
||||
/* TODO: Use table-condensed if xs screen */
|
|
@ -0,0 +1,9 @@
|
|||
.titleImage {
|
||||
height: 46px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.submit {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
|
@ -1,248 +0,0 @@
|
|||
/* Firefox hack for responsive table */
|
||||
@-moz-document url-prefix() {
|
||||
fieldset {
|
||||
display: table-cell;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sidebar
|
||||
*/
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
display: block;
|
||||
padding: 20px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
|
||||
background-color: #333;
|
||||
color: white;
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
|
||||
/* Sidebar elements */
|
||||
.sidebar a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.sidebar h1 {
|
||||
margin: 0;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.sidebar h1 img {
|
||||
height: 46px;
|
||||
}
|
||||
|
||||
.sidebar h1 a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Sidebar navigation */
|
||||
.sidebar .navbar {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.nav-sidebar {
|
||||
margin-right: -20px;
|
||||
margin-bottom: 20px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
.nav-sidebar > li > a {
|
||||
padding-right: 20px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.sidebar,
|
||||
.sidebar .navbar .container-fluid {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.sidebar .nav-list {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.sidebar .nav-sidebar > li > a {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.sidebar .nav-list > li > a {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-sidebar .nav-sidebar {
|
||||
margin-bottom: 0; /* No margin bottom for nested nav-sidebar. */
|
||||
}
|
||||
|
||||
.nav-sidebar > .active > a:focus,
|
||||
.nav > li > a:focus {
|
||||
color: #fff;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.nav-sidebar > .active > a,
|
||||
.nav-sidebar > .active > a:hover,
|
||||
.nav > li > a:hover {
|
||||
color: #fff;
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
.nav > li > a.active {
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
.icon-navbar {
|
||||
background-color: #555;
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
.icon-navbar-nav {
|
||||
display: inline-block;
|
||||
float: none;
|
||||
vertical-align: top;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main content
|
||||
*/
|
||||
.main-panel {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.main-panel {
|
||||
padding-right: 40px;
|
||||
padding-left: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Filtering field
|
||||
*/
|
||||
div.filter {
|
||||
margin-bottom: 34px;
|
||||
}
|
||||
|
||||
.filter-legend {
|
||||
text-align: right;
|
||||
line-height: 34px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.filter-legend {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 767px) {
|
||||
.filter .form-group {
|
||||
width: 75%;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Placeholder dashboard ideas
|
||||
*/
|
||||
.placeholders {
|
||||
margin-bottom: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.placeholders h4 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.placeholder img:hover {
|
||||
transform: scale(1.1);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pager
|
||||
*/
|
||||
.pagination-nav {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pagination > li > span {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login screen
|
||||
*/
|
||||
.login h1 img {
|
||||
height: 46px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.login .submit {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Misc
|
||||
*/
|
||||
|
||||
.art {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
width: 75%;
|
||||
height: auto;
|
||||
|
||||
/* doiuse-disable viewport-units */
|
||||
|
||||
max-width: 25vw;
|
||||
max-height: 25vw;
|
||||
|
||||
/* doiuse-enable viewport-units */
|
||||
}
|
||||
|
||||
.albumRow {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.artistNameRow h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.artistNameRow hr {
|
||||
margin-top: 0.5em; /* Default value. */
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.table-responsive {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.albumRowName h2 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.albumRowArt p,
|
||||
.albumRowArt img {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.albumRowName,
|
||||
.albumRowArt {
|
||||
float: none;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Use table-condensed if xs screen */
|
|
@ -0,0 +1,7 @@
|
|||
:global {
|
||||
@media (max-width: 767px) {
|
||||
.table-responsive {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
:global {
|
||||
/* Firefox hack for responsive table */
|
||||
@-moz-document url-prefix() {
|
||||
fieldset {
|
||||
display: table-cell;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./hacks.scss";
|
||||
export * from "./common.scss";
|
|
@ -0,0 +1,20 @@
|
|||
.filter {
|
||||
margin-bottom: 34px;
|
||||
}
|
||||
|
||||
.legend {
|
||||
text-align: right;
|
||||
line-height: 34px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.legend {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 767px) {
|
||||
.form-group {
|
||||
width: 75%;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
.placeholders {
|
||||
margin-bottom: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.name {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.art {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
width: 75%;
|
||||
height: auto;
|
||||
|
||||
/* doiuse-disable viewport-units */
|
||||
|
||||
max-width: 25vw;
|
||||
|
||||
/* doiuse-enable viewport-units */
|
||||
}
|
||||
|
||||
.art:hover {
|
||||
transform: scale(1.1);
|
||||
cursor: pointer;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
.nav {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
$background: #333;
|
||||
$hoverBackground: #222;
|
||||
$activeBackground: $hoverBackground;
|
||||
$foreground: white;
|
||||
$lightgrey: #eee;
|
||||
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
display: block;
|
||||
padding: 20px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
|
||||
background-color: $background;
|
||||
color: white;
|
||||
border-right: 1px solid $lightgrey;
|
||||
}
|
||||
|
||||
/* Sidebar elements */
|
||||
.link {
|
||||
color: $foreground;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.link:hover,
|
||||
.link:focus {
|
||||
color: $foreground;
|
||||
background-color: $hoverBackground !important; /* TODO: important */
|
||||
}
|
||||
|
||||
.active {
|
||||
composes: link;
|
||||
background-color: $activeBackground;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.imgTitle {
|
||||
height: 46px;
|
||||
}
|
||||
|
||||
/* Sidebar navigation */
|
||||
.icon-navbar {
|
||||
background-color: #555;
|
||||
font-size: 1.25em;
|
||||
border: none;
|
||||
|
||||
.nav {
|
||||
display: inline-block;
|
||||
float: none;
|
||||
vertical-align: top;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Main content
|
||||
*/
|
||||
.main-panel {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Media queries
|
||||
* TODO: Sidebar responsiveness
|
||||
*/
|
||||
/*@media (max-width: 991px) {
|
||||
.sidebar,
|
||||
.sidebar .navbar .container-fluid {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.sidebar .nav-list {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.sidebar .nav-sidebar > li > a {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.sidebar .nav-list > li > a {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.main-panel {
|
||||
padding-right: 40px;
|
||||
padding-left: 40px;
|
||||
}
|
||||
}*/
|
|
@ -4,7 +4,6 @@ then
|
|||
against=HEAD
|
||||
else
|
||||
# Initial commit
|
||||
# TODO
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
@ -17,5 +16,7 @@ then
|
|||
fi
|
||||
|
||||
echo "Rebuilding dist JavaScript files…"
|
||||
NODE_ENV=production npm run build
|
||||
export NODE_ENV=production
|
||||
npm run clean
|
||||
npm run build
|
||||
git add app/dist
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
// Export
|
||||
import "bootstrap";
|
||||
import "bootstrap/dist/css/bootstrap.css";
|
||||
import "./app/styles/ampache.css";
|
||||
|
||||
// Handle app init
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
|
10
package.json
10
package.json
|
@ -11,12 +11,13 @@
|
|||
"watch": "./node_modules/.bin/webpack --progress --watch",
|
||||
"prod": "NODE_ENV=production ./node_modules/.bin/webpack --progress",
|
||||
"extractTranslations": "./node_modules/.bin/babel-node scripts/extractTranslations.js",
|
||||
"clean": "./node_modules/.bin/rimraf app/dist"
|
||||
"clean": "./node_modules/.bin/rimraf .cache && ./node_modules/.bin/rimraf app/dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-polyfill": "^6.9.1",
|
||||
"babel-preset-es2015": "^6.9.0",
|
||||
"bootstrap": "^3.3.6",
|
||||
"bootstrap-loader": "^1.0.10",
|
||||
"bootstrap-sass": "^3.3.7",
|
||||
"fuse.js": "^2.3.0",
|
||||
"html5shiv": "^3.7.3",
|
||||
"humps": "^1.1.0",
|
||||
|
@ -29,6 +30,7 @@
|
|||
"jssha": "^2.1.0",
|
||||
"lodash": "^4.13.1",
|
||||
"react": "^15.2.0",
|
||||
"react-css-modules": "^3.7.9",
|
||||
"react-dom": "^15.2.0",
|
||||
"react-intl": "^2.1.3",
|
||||
"react-redux": "^4.4.5",
|
||||
|
@ -44,7 +46,6 @@
|
|||
"babel-core": "^6.10.4",
|
||||
"babel-loader": "^6.2.4",
|
||||
"babel-plugin-react-intl": "^2.1.3",
|
||||
"babel-plugin-transform-runtime": "^6.12.0",
|
||||
"babel-preset-react": "^6.11.1",
|
||||
"css-loader": "^0.23.1",
|
||||
"doiuse": "^2.4.1",
|
||||
|
@ -55,6 +56,7 @@
|
|||
"extract-text-webpack-plugin": "^1.0.1",
|
||||
"file-loader": "^0.9.0",
|
||||
"glob": "^7.0.5",
|
||||
"node-sass": "^3.8.0",
|
||||
"postcss": "^5.1.0",
|
||||
"postcss-loader": "^0.9.1",
|
||||
"postcss-reporter": "^1.4.1",
|
||||
|
@ -63,7 +65,9 @@
|
|||
"react-intl-webpack-plugin": "0.0.3",
|
||||
"redbox-react": "^1.2.10",
|
||||
"redux-logger": "^2.6.1",
|
||||
"resolve-url-loader": "^1.6.0",
|
||||
"rimraf": "^2.5.4",
|
||||
"sass-loader": "^4.0.0",
|
||||
"style-loader": "^0.13.1",
|
||||
"stylelint": "^7.0.3",
|
||||
"stylelint-config-standard": "^11.0.0",
|
||||
|
|
|
@ -11,7 +11,7 @@ var browsers = ["ie >= 9", "> 1%", "last 3 versions", "not op_mini all"];
|
|||
|
||||
module.exports = {
|
||||
entry: {
|
||||
"index": ["babel-polyfill", "./index.js"],
|
||||
"index": ["babel-polyfill", "bootstrap-loader", "./app/styles/common/index.js", "./index.js"],
|
||||
"fix.ie9": "./fix.ie9.js"
|
||||
},
|
||||
|
||||
|
@ -40,24 +40,22 @@ module.exports = {
|
|||
},
|
||||
include: __dirname
|
||||
},
|
||||
// Do not postcss vendor modules
|
||||
{
|
||||
test: /\.css$/,
|
||||
exclude: /node_modules/,
|
||||
loader: ExtractTextPlugin.extract("style-loader", "css-loader!postcss-loader")
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
exclude: /app/,
|
||||
loader: ExtractTextPlugin.extract("style-loader", "css-loader")
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")
|
||||
loader: ExtractTextPlugin.extract(
|
||||
"style-loader",
|
||||
"css-loader?modules&importLoaders=1&localIdentName=[name]__[local]__[hash:base64:5]" +
|
||||
"!postcss-loader"
|
||||
)
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
loader: ExtractTextPlugin.extract("style-loader", "css-loader!sass-loader")
|
||||
loader: ExtractTextPlugin.extract(
|
||||
"style-loader",
|
||||
"css-loader?modules&importLoaders=1&localIdentName=[name]__[local]__[hash:base64:5]" +
|
||||
// TODO: "!postcss-loader" +
|
||||
"!sass-loader"
|
||||
)
|
||||
},
|
||||
{
|
||||
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
|
||||
|
@ -86,9 +84,7 @@ module.exports = {
|
|||
new ExtractTextPlugin("style.css", { allChunks: true })
|
||||
],
|
||||
|
||||
postcss: function () {
|
||||
return [doiuse({ browsers: browsers }), stylelint, precss, autoprefixer({ browsers: browsers }), postcssReporter({ throwError: true, clearMessages: true })];
|
||||
},
|
||||
postcss: [doiuse({ browsers: browsers }), stylelint, precss, autoprefixer({ browsers: browsers }), postcssReporter({ throwError: true, clearMessages: true })],
|
||||
|
||||
resolve: {
|
||||
// Include empty string "" to resolve files by their explicit extension
|
||||
|
|
|
@ -4,9 +4,9 @@ var config = require("./webpack.config.base.js");
|
|||
config.devtool = "cheap-module-eval-source-map";
|
||||
|
||||
// necessary for hot reloading with IE:
|
||||
config.entry.eventsourcePolyfill = 'eventsource-polyfill';
|
||||
config.entry.index.splice(1, 0, 'eventsource-polyfill');
|
||||
// listen to code updates emitted by hot middleware:
|
||||
config.entry.webpackHotMiddlewareClient = 'webpack-hot-middleware/client';
|
||||
config.entry.index.splice(2, 0, 'webpack-hot-middleware/client');
|
||||
|
||||
config.plugins = config.plugins.concat([
|
||||
new webpack.HotModuleReplacementPlugin()
|
||||
|
|
Laddar…
Referens i nytt ärende