Feat: anon navbar (#16189)
* chore(React): %s/react-pure-render/React.PureComponent/gc * fix(Settings): Should redirect to signup when unauthen * feat(Development): Use SES for mail if defined * feat(Nav): Show anon navbar when logged in * fix(server/datasources): Make sure mailhog works if no ses keys are found LB will use both mail settings if using both local and dev * fix(Nav): Use text instead of icons * fix(Nav): Make donate page open in new tab
This commit is contained in:
committed by
Quincy Larson
parent
1720c61753
commit
b1e9a172a2
@ -1,10 +1,14 @@
|
|||||||
import { types } from '../../common/app/redux';
|
import _ from 'lodash';
|
||||||
import { ofType } from 'redux-epic';
|
import { ofType } from 'redux-epic';
|
||||||
|
|
||||||
export default function hardGoToSaga(actions, _, { history }) {
|
import { types } from '../../common/app/redux';
|
||||||
|
|
||||||
|
export default function hardGoToSaga(actions, store, { location }) {
|
||||||
return actions::ofType(types.hardGoTo)
|
return actions::ofType(types.hardGoTo)
|
||||||
.map(({ payload = '/settings' }) => {
|
.pluck('payload')
|
||||||
history.pushState(history.state, null, payload);
|
.filter(_.isString)
|
||||||
return null;
|
.do((payload = '/') => {
|
||||||
});
|
location.pathname = payload;
|
||||||
|
})
|
||||||
|
.ignoreElements();
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import React from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import FA from 'react-fontawesome';
|
import FA from 'react-fontawesome';
|
||||||
import PureComponent from 'react-pure-render/component';
|
|
||||||
import { Panel } from 'react-bootstrap';
|
import { Panel } from 'react-bootstrap';
|
||||||
|
|
||||||
import ns from './ns.json';
|
import ns from './ns.json';
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import PureComponent from 'react-pure-render/component';
|
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import PureComponent from 'react-pure-render/component';
|
|
||||||
import { Col, Row } from 'react-bootstrap';
|
import { Col, Row } from 'react-bootstrap';
|
||||||
|
|
||||||
import ns from './ns.json';
|
import ns from './ns.json';
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import PureComponent from 'react-pure-render/component';
|
|
||||||
import FA from 'react-fontawesome';
|
import FA from 'react-fontawesome';
|
||||||
import { Panel } from 'react-bootstrap';
|
import { Panel } from 'react-bootstrap';
|
||||||
|
|
||||||
|
@ -27,24 +27,18 @@ import {
|
|||||||
|
|
||||||
dropdownSelector
|
dropdownSelector
|
||||||
} from './redux';
|
} from './redux';
|
||||||
import {
|
import { isSignedInSelector, signInLoadingSelector } from '../redux';
|
||||||
userSelector,
|
|
||||||
isSignedInSelector,
|
|
||||||
signInLoadingSelector
|
|
||||||
} from '../redux';
|
|
||||||
import { panesSelector } from '../Panes/redux';
|
import { panesSelector } from '../Panes/redux';
|
||||||
|
|
||||||
|
|
||||||
const fCClogo = 'https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg';
|
const fCClogo = 'https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg';
|
||||||
|
|
||||||
const mapStateToProps = createSelector(
|
const mapStateToProps = createSelector(
|
||||||
userSelector,
|
|
||||||
isSignedInSelector,
|
isSignedInSelector,
|
||||||
dropdownSelector,
|
dropdownSelector,
|
||||||
signInLoadingSelector,
|
signInLoadingSelector,
|
||||||
panesSelector,
|
panesSelector,
|
||||||
(
|
(
|
||||||
{ username, picture, points },
|
|
||||||
isSignedIn,
|
isSignedIn,
|
||||||
isDropdownOpen,
|
isDropdownOpen,
|
||||||
showLoading,
|
showLoading,
|
||||||
@ -59,10 +53,7 @@ const mapStateToProps = createSelector(
|
|||||||
}, {}),
|
}, {}),
|
||||||
isDropdownOpen,
|
isDropdownOpen,
|
||||||
isSignedIn,
|
isSignedIn,
|
||||||
picture,
|
showLoading
|
||||||
points,
|
|
||||||
showLoading,
|
|
||||||
username
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -111,13 +102,11 @@ const propTypes = {
|
|||||||
clickOnMap: PropTypes.func.isRequired,
|
clickOnMap: PropTypes.func.isRequired,
|
||||||
closeDropdown: PropTypes.func.isRequired,
|
closeDropdown: PropTypes.func.isRequired,
|
||||||
isDropdownOpen: PropTypes.bool,
|
isDropdownOpen: PropTypes.bool,
|
||||||
|
isSignedIn: PropTypes.bool,
|
||||||
openDropdown: PropTypes.func.isRequired,
|
openDropdown: PropTypes.func.isRequired,
|
||||||
panes: PropTypes.array,
|
panes: PropTypes.array,
|
||||||
picture: PropTypes.string,
|
|
||||||
points: PropTypes.number,
|
|
||||||
showLoading: PropTypes.bool,
|
showLoading: PropTypes.bool,
|
||||||
signedIn: PropTypes.bool,
|
signedIn: PropTypes.bool
|
||||||
username: PropTypes.string
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export class FCCNav extends React.Component {
|
export class FCCNav extends React.Component {
|
||||||
@ -178,11 +167,9 @@ export class FCCNav extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
panes,
|
panes,
|
||||||
|
isSignedIn,
|
||||||
clickOnLogo,
|
clickOnLogo,
|
||||||
clickOnMap,
|
clickOnMap,
|
||||||
username,
|
|
||||||
points,
|
|
||||||
picture,
|
|
||||||
showLoading
|
showLoading
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@ -236,10 +223,8 @@ export class FCCNav extends React.Component {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
<SignUp
|
<SignUp
|
||||||
picture={ picture }
|
|
||||||
points={ points }
|
|
||||||
showLoading={ showLoading }
|
showLoading={ showLoading }
|
||||||
username={ username }
|
showSignUp={ !isSignedIn }
|
||||||
/>
|
/>
|
||||||
</Nav>
|
</Nav>
|
||||||
</Navbar.Collapse>
|
</Navbar.Collapse>
|
||||||
|
@ -5,26 +5,16 @@ import { NavItem } from 'react-bootstrap';
|
|||||||
import { Link } from '../Router';
|
import { Link } from '../Router';
|
||||||
import { onRouteSettings } from '../routes/Settings/redux';
|
import { onRouteSettings } from '../routes/Settings/redux';
|
||||||
|
|
||||||
// this is separated out to prevent react bootstrap's
|
|
||||||
// NavBar from injecting unknown props to the li component
|
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
picture: PropTypes.string,
|
|
||||||
points: PropTypes.number,
|
|
||||||
showLoading: PropTypes.bool,
|
showLoading: PropTypes.bool,
|
||||||
username: PropTypes.string
|
showSignUp: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function SignUpButton({
|
export default function SignUpButton({ showLoading, showSignUp }) {
|
||||||
picture,
|
|
||||||
points,
|
|
||||||
showLoading,
|
|
||||||
username
|
|
||||||
}) {
|
|
||||||
if (showLoading) {
|
if (showLoading) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!username) {
|
if (showSignUp) {
|
||||||
return (
|
return (
|
||||||
<NavItem
|
<NavItem
|
||||||
href='/signup'
|
href='/signup'
|
||||||
@ -40,14 +30,7 @@ export default function SignUpButton({
|
|||||||
key='user'
|
key='user'
|
||||||
>
|
>
|
||||||
<Link to={ onRouteSettings() }>
|
<Link to={ onRouteSettings() }>
|
||||||
<span className='nav-username hidden-sm'> { username } </span>
|
My Profile
|
||||||
<span className='nav-points'> [ { points || 1 } ] </span>
|
|
||||||
<span className='nav-picture-container'>
|
|
||||||
<img
|
|
||||||
className='nav-picture float-right'
|
|
||||||
src={ picture }
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"content": "Donate",
|
"content": "Donate",
|
||||||
"link": "https://www.freecodecamp.org/donate"
|
"link": "https://www.freecodecamp.org/donate",
|
||||||
|
"target": "_blank"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -77,31 +77,10 @@ li.nav-avatar {
|
|||||||
|
|
||||||
> a {
|
> a {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 @navbar-padding-horizontal 0 @navbar-padding-horizontal;
|
padding: 7.5px @navbar-padding-horizontal 7.5px @navbar-padding-horizontal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-username {
|
|
||||||
padding-right: @navbar-padding-horizontal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-points {
|
|
||||||
@media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {
|
|
||||||
padding: @navbar-padding-vertical 0 @navbar-padding-vertical 0;
|
|
||||||
}
|
|
||||||
@media (min-width: @screen-md-min) {
|
|
||||||
padding: @navbar-padding-vertical @navbar-padding-horizontal @navbar-padding-vertical 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-picture {
|
|
||||||
margin-top: @navbar-logo-padding;
|
|
||||||
margin-bottom: @navbar-logo-padding;
|
|
||||||
height: @navbar-logo-height;
|
|
||||||
width: @navbar-logo-height;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-nav a {
|
.navbar-nav a {
|
||||||
color: @body-bg;
|
color: @body-bg;
|
||||||
margin-top: -5px;
|
margin-top: -5px;
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Button, Modal } from 'react-bootstrap';
|
import { Button, Modal } from 'react-bootstrap';
|
||||||
import PureComponent from 'react-pure-render/component';
|
|
||||||
|
|
||||||
import ns from './ns.json';
|
import ns from './ns.json';
|
||||||
import {
|
import {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import React from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import PureComponent from 'react-pure-render/component';
|
|
||||||
import { Grid, Col, Row } from 'react-bootstrap';
|
import { Grid, Col, Row } from 'react-bootstrap';
|
||||||
|
|
||||||
import ns from './ns.json';
|
import ns from './ns.json';
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import React from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ReactDom from 'react-dom';
|
import ReactDom from 'react-dom';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import PureComponent from 'react-pure-render/component';
|
|
||||||
|
|
||||||
import ns from './ns.json';
|
import ns from './ns.json';
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import PureComponent from 'react-pure-render/component';
|
|
||||||
import { Col, Image } from 'react-bootstrap';
|
import { Col, Image } from 'react-bootstrap';
|
||||||
|
|
||||||
import SidePanel from './Side-Panel.jsx';
|
import SidePanel from './Side-Panel.jsx';
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import React from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import PureComponent from 'react-pure-render/component';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
|
@ -21,7 +21,8 @@ import {
|
|||||||
|
|
||||||
signInLoadingSelector,
|
signInLoadingSelector,
|
||||||
userSelector,
|
userSelector,
|
||||||
themeSelector
|
themeSelector,
|
||||||
|
hardGoTo
|
||||||
} from '../../redux';
|
} from '../../redux';
|
||||||
import ChildContainer from '../../Child-Container.jsx';
|
import ChildContainer from '../../Child-Container.jsx';
|
||||||
|
|
||||||
@ -64,6 +65,7 @@ const mapStateToProps = createSelector(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
|
hardGoTo,
|
||||||
toggleIsAvailableForHire: () => toggleUserFlag('isAvailableForHire'),
|
toggleIsAvailableForHire: () => toggleUserFlag('isAvailableForHire'),
|
||||||
toggleIsLocked: () => toggleUserFlag('isLocked'),
|
toggleIsLocked: () => toggleUserFlag('isLocked'),
|
||||||
toggleMonthlyEmail: () => toggleUserFlag('sendMonthlyEmail'),
|
toggleMonthlyEmail: () => toggleUserFlag('sendMonthlyEmail'),
|
||||||
@ -77,6 +79,7 @@ const propTypes = {
|
|||||||
children: PropTypes.element,
|
children: PropTypes.element,
|
||||||
currentTheme: PropTypes.string,
|
currentTheme: PropTypes.string,
|
||||||
email: PropTypes.string,
|
email: PropTypes.string,
|
||||||
|
hardGoTo: PropTypes.func.isRequired,
|
||||||
initialLang: PropTypes.string,
|
initialLang: PropTypes.string,
|
||||||
isAvailableForHire: PropTypes.bool,
|
isAvailableForHire: PropTypes.bool,
|
||||||
isGithubCool: PropTypes.bool,
|
isGithubCool: PropTypes.bool,
|
||||||
@ -115,6 +118,11 @@ export class Settings extends React.Component {
|
|||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.props.updateTitle('Settings');
|
this.props.updateTitle('Settings');
|
||||||
}
|
}
|
||||||
|
componentWillReceiveProps({ username, showLoading, hardGoTo }) {
|
||||||
|
if (!username && !showLoading) {
|
||||||
|
hardGoTo('/signup');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
@ -138,7 +146,7 @@ export class Settings extends React.Component {
|
|||||||
toggleQuincyEmail,
|
toggleQuincyEmail,
|
||||||
username
|
username
|
||||||
} = this.props;
|
} = this.props;
|
||||||
if (!username && !showLoading) {
|
if (!username && showLoading) {
|
||||||
return <SettingsSkeleton />;
|
return <SettingsSkeleton />;
|
||||||
}
|
}
|
||||||
if (showUpdateEmailView) {
|
if (showUpdateEmailView) {
|
||||||
|
11
package-lock.json
generated
11
package-lock.json
generated
@ -5391,9 +5391,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"font-awesome": {
|
"font-awesome": {
|
||||||
"version": "4.5.0",
|
"version": "4.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz",
|
||||||
"integrity": "sha1-Hp18z31jvb5XAA4Y1RiMslV+cPg="
|
"integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM="
|
||||||
},
|
},
|
||||||
"for-each": {
|
"for-each": {
|
||||||
"version": "0.3.2",
|
"version": "0.3.2",
|
||||||
@ -12781,11 +12781,6 @@
|
|||||||
"warning": "3.0.0"
|
"warning": "3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-pure-render": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-pure-render/-/react-pure-render-1.0.2.tgz",
|
|
||||||
"integrity": "sha1-nYqSjH8sN1E8LQZOV7Pjw1bp+rs="
|
|
||||||
},
|
|
||||||
"react-redux": {
|
"react-redux": {
|
||||||
"version": "4.4.8",
|
"version": "4.4.8",
|
||||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-4.4.8.tgz",
|
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-4.4.8.tgz",
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
"express-state": "^1.2.0",
|
"express-state": "^1.2.0",
|
||||||
"express-validator": "^3.0.0",
|
"express-validator": "^3.0.0",
|
||||||
"fetchr": "~0.5.12",
|
"fetchr": "~0.5.12",
|
||||||
"font-awesome": "~4.5.0",
|
"font-awesome": "^4.7.0",
|
||||||
"frameguard": "^3.0.0",
|
"frameguard": "^3.0.0",
|
||||||
"googleapis": "16.1.0",
|
"googleapis": "16.1.0",
|
||||||
"helmet": "^3.1.0",
|
"helmet": "^3.1.0",
|
||||||
@ -115,7 +115,6 @@
|
|||||||
"react-motion": "~0.4.2",
|
"react-motion": "~0.4.2",
|
||||||
"react-no-ssr": "^1.0.1",
|
"react-no-ssr": "^1.0.1",
|
||||||
"react-notification": "git+https://github.com/BerkeleyTrue/react-notification.git#freecodecamp",
|
"react-notification": "git+https://github.com/BerkeleyTrue/react-notification.git#freecodecamp",
|
||||||
"react-pure-render": "^1.0.2",
|
|
||||||
"react-redux": "^4.0.6",
|
"react-redux": "^4.0.6",
|
||||||
"react-test-renderer": "^15.6.2",
|
"react-test-renderer": "^15.6.2",
|
||||||
"react-youtube": "^7.0.0",
|
"react-youtube": "^7.0.0",
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
module.exports = {
|
const debug = require('debug')('fcc:server:datasources');
|
||||||
mail: {
|
const dsLocal = require('./datasources.production.js');
|
||||||
|
|
||||||
|
const ds = {
|
||||||
|
...dsLocal
|
||||||
|
};
|
||||||
|
// use [MailHog](https://github.com/mailhog/MailHog) if no SES keys are found
|
||||||
|
if (!process.env.SES_ID) {
|
||||||
|
ds.mail = {
|
||||||
connector: 'mail',
|
connector: 'mail',
|
||||||
transport: {
|
transport: {
|
||||||
type: 'smtp',
|
type: 'smtp',
|
||||||
@ -14,5 +21,9 @@ module.exports = {
|
|||||||
user: 'test',
|
user: 'test',
|
||||||
pass: 'test'
|
pass: 'test'
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
debug(`using MailHog server on port ${ds.mail.transport.port}`);
|
||||||
|
} else {
|
||||||
|
debug('using AWS SES to deliver emails');
|
||||||
|
}
|
||||||
|
module.exports = ds;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
nav.navbar.navbar-default.navbar-static-top.nav-height
|
nav.navbar.navbar-default.navbar-static-top.nav-height
|
||||||
|
|
||||||
.navbar-header
|
.navbar-header
|
||||||
button.hamburger.navbar-toggle(type='button', data-toggle='collapse', data-target='.navbar-collapse')
|
button.hamburger.navbar-toggle(type='button', data-toggle='collapse', data-target='.navbar-collapse')
|
||||||
.col-xs-12
|
.col-xs-12
|
||||||
@ -25,10 +26,10 @@ nav.navbar.navbar-default.navbar-static-top.nav-height
|
|||||||
li
|
li
|
||||||
a(href='/map') Map
|
a(href='/map') Map
|
||||||
li
|
li
|
||||||
a(href='https://www.freecodecamp.org/donate') Donate
|
a(href='https://www.freecodecamp.org/donate', target='_blank') Donate
|
||||||
if !user
|
if !user
|
||||||
li
|
li
|
||||||
a(href='/signin') Sign In
|
a(href='/signin') Sign Up
|
||||||
else
|
else
|
||||||
li.nav-avatar
|
li.nav-avatar
|
||||||
a(href='/settings')
|
a(href='/settings')
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
link(rel='stylesheet', type='text/css' href='/css/lato.css')
|
link(rel='stylesheet', type='text/css' href='/css/lato.css')
|
||||||
link(rel='stylesheet', type='text/css' href='/css/ubuntu.css')
|
link(rel='stylesheet', type='text/css' href='/css/ubuntu.css')
|
||||||
link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css')
|
link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css')
|
||||||
link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.30.0/codemirror.min.css')
|
link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.30.0/codemirror.min.css')
|
||||||
link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.30.0/addon/lint/lint.min.css')
|
link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.30.0/addon/lint/lint.min.css')
|
||||||
link(rel='stylesheet', href=rev('/css', 'main.css'))
|
link(rel='stylesheet', href=rev('/css', 'main.css'))
|
||||||
|
Reference in New Issue
Block a user