diff --git a/.eslintrc b/.eslintrc index 9e1b57f9a..39a03d571 100644 --- a/.eslintrc +++ b/.eslintrc @@ -26,6 +26,9 @@ "es6": true, "jest": true }, + "globals": { + "__APP_VERSION__": true + }, "rules": { "no-tabs": 0, "keyword-spacing": 0, diff --git a/src/webui/src/components/Footer/footer.scss b/src/webui/src/components/Footer/footer.scss new file mode 100644 index 000000000..e6283e550 --- /dev/null +++ b/src/webui/src/components/Footer/footer.scss @@ -0,0 +1,41 @@ +@import '../../styles/variable'; + +.wrap { + margin-top: auto; + border-top: 1px solid $border-color; + background: #f9f9f9; +} +footer.footer { + display: flex; + margin-top: 0; + padding: 20px 0; + font-size: 14px; + line-height: 18px; + height: 18px; + color: #999; + + span { + display: inline-block; + height: 18px; + vertical-align: middle; + } + + :global { + .emoji { + width: 18px; + height: 18px; + } + [data-type="flags"] .emoji { + margin-left: 8px; + } + } + + .right { + margin-left: auto; + } + .logo { + vertical-align: top; + height: 18px; + width: 20px; + } +} diff --git a/src/webui/src/components/Footer/index.js b/src/webui/src/components/Footer/index.js new file mode 100644 index 000000000..cb07b1660 --- /dev/null +++ b/src/webui/src/components/Footer/index.js @@ -0,0 +1,44 @@ +import React from 'react'; + +import classes from './footer.scss'; +import logo from './logo.svg'; + +export default class Footer extends React.Component { + componentDidMount() { + // Scripts inserted at top of `template/index.html` + if (typeof window.twemoji === 'object' && typeof window.twemoji.parse === 'function') { + window.twemoji.parse(document.getElementById('global-footer'), { + // JSDeliver is the fattest open source cdn in all region, see https://www.jsdelivr.com/network + base: 'https://cdn.jsdelivr.net/npm/twemoji@2.5.0/2/', + ext: '.svg', + size: 'svg' + }); + } + } + + render() { + return ( +
+ +
+ ); + } +} diff --git a/src/webui/src/components/Footer/logo.svg b/src/webui/src/components/Footer/logo.svg new file mode 100644 index 000000000..80985c9f3 --- /dev/null +++ b/src/webui/src/components/Footer/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/webui/src/components/PackageList/packageList.scss b/src/webui/src/components/PackageList/packageList.scss index 899403208..2bf00468d 100644 --- a/src/webui/src/components/PackageList/packageList.scss +++ b/src/webui/src/components/PackageList/packageList.scss @@ -5,6 +5,10 @@ li { border-bottom: 1px solid #e4e8f1; list-style: none; + + &:last-child { + border-bottom: none; + } } .listTitle { diff --git a/src/webui/src/router.js b/src/webui/src/router.js index e918f6f30..c732eb154 100644 --- a/src/webui/src/router.js +++ b/src/webui/src/router.js @@ -4,11 +4,12 @@ import {HashRouter as Router, Route, Switch} from 'react-router-dom'; import Header from './components/Header'; import Home from './modules/home'; import Detail from './modules/detail'; +import Footer from './components/Footer'; const RouterApp = () => { return ( -
+
@@ -17,6 +18,7 @@ const RouterApp = () => {
+
); diff --git a/src/webui/src/styles/global.scss b/src/webui/src/styles/global.scss index 54bfd514e..c5f8528f8 100644 --- a/src/webui/src/styles/global.scss +++ b/src/webui/src/styles/global.scss @@ -22,4 +22,10 @@ ul { margin-top: 0 !important; } } + + .page-full-height { + display: flex; + flex-direction: column; + min-height: 100vh; + } } diff --git a/src/webui/template/index.html b/src/webui/template/index.html index 02022ad79..96e85d88d 100644 --- a/src/webui/template/index.html +++ b/src/webui/template/index.html @@ -8,6 +8,7 @@ +
diff --git a/tools/getPackageVersion.js b/tools/getPackageVersion.js new file mode 100644 index 000000000..f54310430 --- /dev/null +++ b/tools/getPackageVersion.js @@ -0,0 +1,9 @@ +import fs from 'fs'; +import path from 'path'; + +export default function getPackageVersion() { + let packageJSON = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'))); + + return packageJSON.version; +} + diff --git a/tools/webpack.config.js b/tools/webpack.config.js index 3c26eb27a..d656fd637 100644 --- a/tools/webpack.config.js +++ b/tools/webpack.config.js @@ -41,7 +41,7 @@ module.exports = { use: 'babel-loader', }, { - test: /\.(jpe?g|png|gif|svg)$/, + test: /\.(jpe?g|png|gif)$/, use: 'file-loader?name=[name].[ext]', }, { diff --git a/tools/webpack.dev.config.babel.js b/tools/webpack.dev.config.babel.js index 6b998e5d2..eaf871257 100644 --- a/tools/webpack.dev.config.babel.js +++ b/tools/webpack.dev.config.babel.js @@ -4,6 +4,7 @@ import FriendlyErrorsPlugin from 'friendly-errors-webpack-plugin'; import baseConfig from './webpack.config'; import env from '../src/config/env'; import StyleLintPlugin from 'stylelint-webpack-plugin'; +import getPackageVersion from './getPackageVersion'; export default { ...baseConfig, @@ -25,6 +26,7 @@ export default { new webpack.DefinePlugin({ '__DEBUG__': true, 'process.env.NODE_ENV': '"development"', + '__APP_VERSION__': `"${getPackageVersion()}"`, }), new HTMLWebpackPlugin({ title: 'Verdaccio', diff --git a/tools/webpack.prod.config.babel.js b/tools/webpack.prod.config.babel.js index 0da8d1d95..8d84a951c 100644 --- a/tools/webpack.prod.config.babel.js +++ b/tools/webpack.prod.config.babel.js @@ -5,6 +5,7 @@ const baseConfig = require('./webpack.config'); const env = require('../src/config/env'); const _ = require('lodash'); const merge = require('webpack-merge'); +import getPackageVersion from './getPackageVersion'; const prodConf = { entry: { @@ -19,6 +20,7 @@ const prodConf = { new webpack.DefinePlugin({ '__DEBUG__': false, 'process.env.NODE_ENV': '"production"', + '__APP_VERSION__': `"${getPackageVersion()}"`, }), new webpack.optimize.UglifyJsPlugin({ sourceMap: true,