diff --git a/ui/docs/customize.md b/ui/docs/customize.md new file mode 100644 index 00000000000..09a86a132df --- /dev/null +++ b/ui/docs/customize.md @@ -0,0 +1,77 @@ +# UI customization +Use a `public/config.json` (or `dist/config.json` after build) file for customizing theme, logos,... + +## Images +Change the image of the logo, login banner, error page, etc. +```json +{ + "logo": "assets/logo.svg", + "banner": "assets/banner.svg", + "error": { + "404": "assets/404.png", + "403": "assets/403.png", + "500": "assets/500.png" + } +} +``` + +- `logo` changes the logo top-left side image. +- `banner` changes the login banner image. +- `error.404` change the image of error Page not found. +- `error.403` change the image of error Forbidden. +- `error.500` change the image of error Internal Server Error. + +## Theme +Customize themes like colors, border color, etc. +```json +{ + "theme": { + "@primary-color": "#1890ff", + "@success-color": "#52c41a", + "@processing-color": "#1890ff", + "@warning-color": "#faad14", + "@error-color": "#f5222d", + "@font-size-base": "14px", + "@heading-color": "rgba(0, 0, 0, 0.85)", + "@text-color": "rgba(0, 0, 0, 0.65)", + "@text-color-secondary": "rgba(0, 0, 0, 0.45)", + "@disabled-color": "rgba(0, 0, 0, 0.25)", + "@border-color-base": "#d9d9d9", + "@logo-width": "256px", + "@logo-height": "64px", + "@banner-width": "700px", + "@banner-height": "110px", + "@error-width": "256px", + "@error-height": "256px" + } +} +``` + +- `@primary-color` change the major background color of the page (background button, icon hover, etc). +- `@success-color` change success state color. +- `@processing-color` change processing state color. Exp: progress status. +- `@warning-color` change warning state color. +- `@error-color` change error state color. +- `@heading-color` change table header color. +- `@text-color` change in major text color. +- `@text-color-secondary` change of secondary text color (breadcrumb icon). +- `@disabled-color` change disable state color (disabled button, switch, etc). +- `@border-color-base` change in major border color. +- `@logo-width` change the width of the logo top-left side. +- `@logo-height` change the height of the logo top-left side. +- `@banner-width` changes the width of the login banner. +- `@banner-height` changes the height of the login banner. +- `@error-width` changes the width of the error image. +- `@error-height` changes the height of the error image. + +Assorted primary theme colours: + +- Blue: #1890FF +- Red: #F5222D +- Yellow: #FAAD14 +- Cyan: #13C2C2 +- Green: #52C41A +- Purple: #722ED1 + +Also, to add other properties, we can add new properties into `theme.config.js` based on the Ant Design Vue Less variable. +Refer: https://www.antdv.com/docs/vue/customize-theme/#Ant-Design-Vue-Less-variables diff --git a/ui/package-lock.json b/ui/package-lock.json index 7f356ff1896..98558677d58 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -6767,7 +6767,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -6814,6 +6813,44 @@ "warning": "^4.0.0" } }, + "antd-theme-generator": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/antd-theme-generator/-/antd-theme-generator-1.2.4.tgz", + "integrity": "sha512-27HCj4NTpbQZGNkz1Ip7RF1p85iSN4izf5rY6rQvytM2shvve9qVLnIwHGdNWvsMPrgOPH5wlu8bauKnh7+6dg==", + "requires": { + "glob": "^7.1.3", + "hash.js": "^1.1.5", + "less": "^3.9.0", + "less-plugin-npm-import": "^2.1.0", + "postcss": "^6.0.21", + "strip-css-comments": "^4.1.0" + }, + "dependencies": { + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "antd-theme-webpack-plugin": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/antd-theme-webpack-plugin/-/antd-theme-webpack-plugin-1.3.6.tgz", + "integrity": "sha512-3cxWiblpZYbkZoghQODjcejQhx0hTu8aSOilWH2nZFtdOoa0ZFXT6u60uzghZiwqFuYqgv0ylMfYGElOmTUdiw==", + "requires": { + "antd-theme-generator": "^1.2.4" + } + }, "any-observable": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", @@ -9547,7 +9584,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -10256,7 +10292,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -10264,8 +10299,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "color-string": { "version": "1.5.3", @@ -12400,7 +12434,6 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "dev": true, "requires": { "prr": "~1.0.1" } @@ -14680,8 +14713,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbol-support-x": { "version": "1.4.2", @@ -14765,7 +14797,6 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, "requires": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -15253,7 +15284,6 @@ "version": "0.5.5", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", - "dev": true, "optional": true }, "import-cwd": { @@ -15894,6 +15924,11 @@ "has": "^1.0.3" } }, + "is-regexp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz", + "integrity": "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==" + }, "is-resolvable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", @@ -17403,7 +17438,6 @@ "version": "3.11.1", "resolved": "https://registry.npmjs.org/less/-/less-3.11.1.tgz", "integrity": "sha512-tlWX341RECuTOvoDIvtFqXsKj072hm3+9ymRBe76/mD6O5ZZecnlAOVDlWAleF2+aohFrxNidXhv2773f6kY7g==", - "dev": true, "requires": { "clone": "^2.1.2", "errno": "^0.1.1", @@ -17420,14 +17454,12 @@ "clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", - "dev": true + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, "optional": true } } @@ -17457,6 +17489,30 @@ } } }, + "less-plugin-npm-import": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/less-plugin-npm-import/-/less-plugin-npm-import-2.1.0.tgz", + "integrity": "sha1-gj5phskzGKmBccqFiEi2vq1Vvz4=", + "requires": { + "promise": "~7.0.1", + "resolve": "~1.1.6" + }, + "dependencies": { + "promise": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.0.4.tgz", + "integrity": "sha1-Nj6EpMNsg1a4kP7WLJHOhdAu1Tk=", + "requires": { + "asap": "~2.0.3" + } + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" + } + } + }, "leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -18397,8 +18453,7 @@ "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { "version": "1.40.0", @@ -18480,8 +18535,7 @@ "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "minimalistic-crypto-utils": { "version": "1.0.1", @@ -21428,7 +21482,6 @@ "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "dev": true, "optional": true, "requires": { "asap": "~2.0.3" @@ -21477,8 +21530,7 @@ "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" }, "ps-list": { "version": "4.1.0", @@ -23989,6 +24041,14 @@ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, + "strip-css-comments": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/strip-css-comments/-/strip-css-comments-4.1.0.tgz", + "integrity": "sha512-azjRwrqk7nK21LU7QuL7DpDyPjvRROQvqPrNyyz6emdzbOh6fsNTvkSvUiThBLzC6+MN90rFu296VbPb/KV+3A==", + "requires": { + "is-regexp": "^2.1.0" + } + }, "strip-dirs": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", @@ -24097,7 +24157,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } diff --git a/ui/package.json b/ui/package.json index 745e5682b7c..5d55c58b900 100644 --- a/ui/package.json +++ b/ui/package.json @@ -39,6 +39,7 @@ "@fortawesome/free-solid-svg-icons": "^5.13.0", "@fortawesome/vue-fontawesome": "^0.1.9", "ant-design-vue": "~1.6.2", + "antd-theme-webpack-plugin": "^1.3.4", "axios": "^0.19.2", "core-js": "^3.6.5", "enquire.js": "^2.1.6", diff --git a/ui/src/assets/403.png b/ui/public/assets/403.png similarity index 100% rename from ui/src/assets/403.png rename to ui/public/assets/403.png diff --git a/ui/src/assets/404.png b/ui/public/assets/404.png similarity index 100% rename from ui/src/assets/404.png rename to ui/public/assets/404.png diff --git a/ui/src/assets/500.png b/ui/public/assets/500.png similarity index 100% rename from ui/src/assets/500.png rename to ui/public/assets/500.png diff --git a/ui/src/assets/banner.svg b/ui/public/assets/banner.svg similarity index 100% rename from ui/src/assets/banner.svg rename to ui/public/assets/banner.svg diff --git a/ui/src/assets/error.png b/ui/public/assets/error.png similarity index 100% rename from ui/src/assets/error.png rename to ui/public/assets/error.png diff --git a/ui/src/assets/logo.svg b/ui/public/assets/logo.svg similarity index 100% rename from ui/src/assets/logo.svg rename to ui/public/assets/logo.svg diff --git a/ui/src/assets/success.png b/ui/public/assets/success.png similarity index 100% rename from ui/src/assets/success.png rename to ui/public/assets/success.png diff --git a/ui/public/config.json b/ui/public/config.json new file mode 100644 index 00000000000..f36e77c582c --- /dev/null +++ b/ui/public/config.json @@ -0,0 +1,47 @@ +{ + "apiBase": "/client/api", + "docBase": "http://docs.cloudstack.apache.org/en/latest", + "appTitle": "CloudStack", + "logo": "assets/logo.svg", + "banner": "assets/banner.svg", + "error": { + "404": "assets/404.png", + "403": "assets/403.png", + "500": "assets/500.png" + }, + "theme": { + "@primary-color": "#1890ff", + "@processing-color": "#1890ff", + "@success-color": "#52c41a", + "@warning-color": "#faad14", + "@error-color": "#f5222d", + "@font-size-base": "14px", + "@heading-color": "rgba(0, 0, 0, 0.85)", + "@text-color": "rgba(0, 0, 0, 0.65)", + "@text-color-secondary": "rgba(0, 0, 0, 0.45)", + "@disabled-color": "rgba(0, 0, 0, 0.25)", + "@border-color-base": "#d9d9d9", + "@border-radius-base": "4px", + "@box-shadow-base": "0 2px 8px rgba(0, 0, 0, 0.15)", + "@logo-width": "256px", + "@logo-height": "64px", + "@login-banner-width": "700px", + "@login-banner-height": "110px", + "@error-width": "256px", + "@error-height": "256px" + }, + "keyboardOptions": { + "us": "label.standard.us.keyboard", + "uk": "label.uk.keyboard", + "fr": "label.french.azerty.keyboard", + "jp": "label.japanese.keyboard", + "sc": "label.simplified.chinese.keyboard" + }, + "plugins": [ + { + "name": "ExamplePlugin", + "icon": "appstore", + "path": "example.html" + } + ] +} diff --git a/ui/public/example.html b/ui/public/example.html new file mode 100644 index 00000000000..594baf1c108 --- /dev/null +++ b/ui/public/example.html @@ -0,0 +1,12 @@ + + +
+ + + +