mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 10:34:17 +00:00
update: all models, core, interface, settings
This commit is contained in:
parent
599e706a23
commit
660d4848cb
3
.gitignore
vendored
3
.gitignore
vendored
@ -9,7 +9,7 @@
|
||||
|
||||
# production
|
||||
/dist
|
||||
|
||||
/.debug
|
||||
# misc
|
||||
.DS_Store
|
||||
|
||||
@ -18,3 +18,4 @@
|
||||
/src/.umi-production
|
||||
/src/.umi-test
|
||||
/.env.local
|
||||
.debug/4.11/.editorconfig
|
||||
|
@ -10,7 +10,13 @@ module.exports = {
|
||||
DarkLogoPath: '/dark_logo.svg',
|
||||
|
||||
api_prefix: 'ycorejs_apiv3',
|
||||
app_settings_storage: 'app_settings'
|
||||
app_settings_storage: 'app_settings',
|
||||
|
||||
appTheme_container: 'app_theme',
|
||||
appTheme_desiredContrast: 4.5,
|
||||
// Contrast level AA = 4.5, Level AAA = 7
|
||||
// Reference: https://www.w3.org/WAI/WCAG21/quickref/?versions=2.0&showtechniques=143#qr-visual-audio-contrast-contrast
|
||||
|
||||
},
|
||||
|
||||
i18n: {
|
||||
|
@ -30,4 +30,5 @@ module.exports = [
|
||||
title: 'Overlay loose focus',
|
||||
description: 'Close the overlay when loose focus',
|
||||
},
|
||||
|
||||
]
|
||||
|
@ -7,7 +7,8 @@ let MenuList = [
|
||||
path: '/main',
|
||||
require: 'login',
|
||||
icon: <Icons.Home />,
|
||||
mobile: 'true'
|
||||
mobile: true,
|
||||
desktop: false
|
||||
},
|
||||
{
|
||||
id: 'explore',
|
||||
@ -15,7 +16,8 @@ let MenuList = [
|
||||
path: '/explore',
|
||||
require: 'login',
|
||||
icon: <Icons.Compass />,
|
||||
mobile: 'true'
|
||||
mobile: true,
|
||||
desktop: true
|
||||
},
|
||||
{
|
||||
id: 'saves',
|
||||
@ -23,7 +25,8 @@ let MenuList = [
|
||||
path: '/saves',
|
||||
require: 'login',
|
||||
icon: <Icons.Bookmark />,
|
||||
mobile: 'false'
|
||||
mobile: false,
|
||||
desktop: true
|
||||
},
|
||||
{
|
||||
id: 'messages',
|
||||
@ -31,7 +34,8 @@ let MenuList = [
|
||||
path: '/messages',
|
||||
require: 'login',
|
||||
icon: <Icons.MessageSquare />,
|
||||
mobile: 'false'
|
||||
mobile: true,
|
||||
desktop: true
|
||||
},
|
||||
{
|
||||
id: 'notifications',
|
||||
@ -39,7 +43,8 @@ let MenuList = [
|
||||
path: '/notifications',
|
||||
require: 'login',
|
||||
icon: <Icons.Inbox/>,
|
||||
mobile: 'false'
|
||||
mobile: true,
|
||||
desktop: true
|
||||
},
|
||||
]
|
||||
|
||||
|
35
globals/theme_settings.js
Normal file
35
globals/theme_settings.js
Normal file
@ -0,0 +1,35 @@
|
||||
import * as Icons from 'components/Icons'
|
||||
|
||||
export default [
|
||||
{
|
||||
id: 'backgroundImage',
|
||||
icon: <Icons.Image />,
|
||||
title: 'Background Image',
|
||||
description: 'Change the background of the app',
|
||||
},
|
||||
{
|
||||
id: 'backgroundColor',
|
||||
icon: <Icons.Droplet />,
|
||||
title: 'Overlay Color',
|
||||
description: 'Description blah blah',
|
||||
},
|
||||
{
|
||||
id: 'color',
|
||||
icon: <Icons.FormatPainterOutlined style={{ marginRight: '10px' }} />,
|
||||
title: 'Colors',
|
||||
description: 'Texts, Buttons, Sliders ...etc',
|
||||
},
|
||||
{
|
||||
id: 'fontSize',
|
||||
icon: <Icons.ZoomIn />,
|
||||
title: 'Sizes',
|
||||
description: 'Zoom?',
|
||||
},
|
||||
{
|
||||
id: 'darkmode',
|
||||
icon: <Icons.Moon />,
|
||||
title: 'Dark Mode',
|
||||
description: 'Yeaah, no more daying',
|
||||
}
|
||||
]
|
||||
|
@ -3,7 +3,7 @@
|
||||
"UUID": "C8mVSr-4nmPp2-pr5Vrz-CU4kg4",
|
||||
"title": "Comty™",
|
||||
"DevBuild": true,
|
||||
"version": "0.7.24",
|
||||
"version": "0.7.31",
|
||||
"stage": "dev-pre",
|
||||
"description": "",
|
||||
"author": "RageStudio",
|
||||
@ -29,15 +29,17 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@icons-pack/react-simple-icons": "^3.8.0",
|
||||
"@lingui/cli": "^2.9.1",
|
||||
"@lingui/loader": "^2.9.1",
|
||||
"@lingui/react": "^2.9.1",
|
||||
"@material-ui/core": "^4.9.9",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@ragestudio/ycorejs-lib": "^0.1.21",
|
||||
"antd": "^4.3.5",
|
||||
"antd": "^4.5.1",
|
||||
"axios": "^0.19.2",
|
||||
"babel-core": "^6.26.3",
|
||||
"big-json": "^3.1.0",
|
||||
"classnames": "^2.2.6",
|
||||
"colorthief": "^2.3.0",
|
||||
"dva-model-extend": "^0.1.2",
|
||||
@ -70,6 +72,7 @@
|
||||
"react-scripts": "^3.4.1",
|
||||
"react-transition-group": "^4.4.1",
|
||||
"react-virtualized": "^9.21.2",
|
||||
"simple-icons": "^3.3.0",
|
||||
"stack-trace": "0.0.10",
|
||||
"store": "^2.0.12",
|
||||
"styled-components": "^5.1.1",
|
||||
|
@ -1,10 +1,10 @@
|
||||
<svg id="e9915989-cca6-4620-8282-9db0f616b757" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 120">
|
||||
<path
|
||||
d="M77.55,29.69,92,18.78a1.42,1.42,0,0,0,.25-2,39.2,39.2,0,0,0-56.31-4.21A38.05,38.05,0,0,0,23.23,42a38.09,38.09,0,0,0,3.62,15.1A38.65,38.65,0,0,0,37.8,70.84,39.46,39.46,0,0,0,83.37,73a38.26,38.26,0,0,0,8.41-7.4,1.41,1.41,0,0,0-.23-2L77.65,53a1.43,1.43,0,0,0-1.9.15A17,17,0,0,1,72.55,56a17.75,17.75,0,0,1-9,2.88c-8.32.31-13.62-5.69-14-6.13a17.68,17.68,0,0,1-4.13-10.13,17.93,17.93,0,0,1,4.56-13A17.46,17.46,0,0,1,71.7,26.34a17.3,17.3,0,0,1,4,3.2A1.41,1.41,0,0,0,77.55,29.69Z"
|
||||
style="fill: #333;"
|
||||
style="fill: rgba(51, 51, 51, 0.80);"
|
||||
/>
|
||||
<path
|
||||
d="M13,63.17a2.77,2.77,0,0,1,3.75,1.43A48.38,48.38,0,0,0,32.07,84.53,48.83,48.83,0,0,0,52.34,93.3,47.37,47.37,0,0,0,92.57,81.8a2.77,2.77,0,0,1,4,.3l6.23,7.4a2.79,2.79,0,0,1-.21,3.83,63.83,63.83,0,0,1-6,5,62.21,62.21,0,0,1-7.44,4.7A60.84,60.84,0,0,1,77,108a62.3,62.3,0,0,1-27,1.51A62.51,62.51,0,0,1,40.18,107,61.5,61.5,0,0,1,20.1,95.69,61.73,61.73,0,0,1,2.41,71a2.79,2.79,0,0,1,1.42-3.55Z"
|
||||
style="fill: #333;"
|
||||
style="fill: rgba(51, 51, 51, 0.80);"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@ -1,4 +1,4 @@
|
||||
export * from 'feather-reactjs'
|
||||
export * from '@ant-design/icons'
|
||||
export * from './custom'
|
||||
|
||||
export * from '@icons-pack/react-simple-icons'
|
||||
|
@ -16,51 +16,45 @@ const animationStyles = {
|
||||
},
|
||||
}
|
||||
|
||||
export function SetControls(e) {
|
||||
window.ControlComponent.DummySetControls(e)
|
||||
return
|
||||
export const control = {
|
||||
set: (e) => {
|
||||
if (!window.ControlComponent.state.active) {
|
||||
window.ControlComponent.setState({ fadein: true })
|
||||
}
|
||||
window.ControlComponent.setState({ active: true, render: e })
|
||||
},
|
||||
close: () => {
|
||||
window.ControlComponent.setState({ fadein: false })
|
||||
setTimeout(() => window.ControlComponent.setState({ active: false, render: null }), 1000)
|
||||
}
|
||||
export function CloseControls() {
|
||||
window.ControlComponent.DummyCloseControls()
|
||||
return
|
||||
}
|
||||
|
||||
class Control extends React.PureComponent {
|
||||
export default class Control extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
window.ControlComponent = this
|
||||
super(props);
|
||||
this.state = {
|
||||
Show: false,
|
||||
FadeIN: true,
|
||||
}
|
||||
}
|
||||
set = e => {
|
||||
if (this.state.Show == false) {
|
||||
this.setState({ FadeIN: true })
|
||||
}
|
||||
this.setState({ Show: true, RenderFragment: e })
|
||||
}
|
||||
close() {
|
||||
this.setState({ FadeIN: false })
|
||||
setTimeout(() => this.setState({ Show: false, RenderFragment: null }), 1000)
|
||||
active: false,
|
||||
fadein: true,
|
||||
};
|
||||
window.ControlComponent = this;
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const { RenderFragment, Show, FadeIN } = this.state
|
||||
const { render, active, fadein } = this.state
|
||||
const isMobile = this.props.mobile? this.props.mobile : false
|
||||
return Show ? (
|
||||
return active ? (
|
||||
<StyleRoot>
|
||||
<div
|
||||
style={
|
||||
FadeIN ? animationStyles.fadeInUp : animationStyles.bounceOutDown
|
||||
fadein ? animationStyles.fadeInUp : animationStyles.bounceOutDown
|
||||
}
|
||||
>
|
||||
<antd.Card bordered={false} className={classnames(styles.ControlCard, {[styles.mobile]: isMobile})} >
|
||||
<React.Fragment>{RenderFragment}</React.Fragment>
|
||||
<React.Fragment>{render}</React.Fragment>
|
||||
</antd.Card>
|
||||
</div>
|
||||
</StyleRoot>
|
||||
) : null
|
||||
}
|
||||
}
|
||||
export default Control
|
||||
|
@ -10,7 +10,7 @@
|
||||
background-color: transparent;
|
||||
border: 0!important;
|
||||
outline: 0!important;
|
||||
color: #273346;
|
||||
color: @AppTheme_global_color_accent;
|
||||
padding: 0 0 0 48px;
|
||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 56.966 56.966' fill='%23c1c7cd'%3e%3cpath d='M55.146 51.887L41.588 37.786A22.926 22.926 0 0046.984 23c0-12.682-10.318-23-23-23s-23 10.318-23 23 10.318 23 23 23c4.761 0 9.298-1.436 13.177-4.162l13.661 14.208c.571.593 1.339.92 2.162.92.779 0 1.518-.297 2.079-.837a3.004 3.004 0 00.083-4.242zM23.984 6c9.374 0 17 7.626 17 17s-7.626 17-17 17-17-7.626-17-17 7.626-17 17-17z'/%3e%3c/svg%3e");
|
||||
background-repeat: no-repeat;
|
||||
@ -20,7 +20,7 @@
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
&::placeholder {
|
||||
color: #a2a2a2;
|
||||
color: @AppTheme_global_color_accent;
|
||||
}
|
||||
transition: all 150ms ease-in-out;
|
||||
|
||||
|
@ -117,7 +117,7 @@ export default class Overlay extends React.PureComponent {
|
||||
}
|
||||
|
||||
return(
|
||||
<Primary id="main" fragment={<> <div><__searchBar /></div> <div><Card_Component> yeah </Card_Component></div> </>} />
|
||||
<Primary id="main" fragment={<> <div><__searchBar /></div> <div></div> </>} />
|
||||
)
|
||||
|
||||
}
|
||||
|
@ -15,12 +15,12 @@ export default class Sider_Default extends React.PureComponent {
|
||||
|
||||
renderMenus(data){
|
||||
return data.map(e => {
|
||||
return(
|
||||
return e.desktop? (
|
||||
<antd.Menu.Item key={e.id}>
|
||||
{e.icon}
|
||||
<span>{e.title}</span>
|
||||
</antd.Menu.Item>
|
||||
)
|
||||
) : null
|
||||
})
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ export default class Sider_Default extends React.PureComponent {
|
||||
>
|
||||
<div className={styles.left_sider_brandholder}>
|
||||
<img
|
||||
onClick={() => handleClickMenu({key: '/'})}
|
||||
onClick={() => handleClickMenu({key: ''})}
|
||||
src={logo}
|
||||
/>
|
||||
</div>
|
||||
|
@ -3,8 +3,9 @@
|
||||
|
||||
.left_sider_wrapper {
|
||||
border-color: transparent;
|
||||
font-size: 13px;
|
||||
font-family: @__Global_general_font_family;
|
||||
font-size: 15px;
|
||||
font-family: @__Global_texted_font;
|
||||
font-weight: 600;
|
||||
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
@ -15,19 +16,13 @@
|
||||
background-color: transparent;
|
||||
backdrop-filter: blur(2px);
|
||||
|
||||
&.matchColor{
|
||||
h1,h2,h3,h4,h5,span,p,svg {
|
||||
color: unset;
|
||||
filter: invert(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
:global {
|
||||
.ant-layout-sider {
|
||||
background-color: transparent;
|
||||
float: right;
|
||||
.ant-menu {
|
||||
font-weight: 700;
|
||||
color: @AppTheme_global_color;
|
||||
vertical-align: middle;
|
||||
// margin: 0 0 0 5px;
|
||||
}
|
||||
@ -47,7 +42,8 @@
|
||||
|
||||
// background: linear-gradient(49deg, rgba(255,255,255,1) 32%, rgba(255, 255, 255, 0) 100%);
|
||||
backdrop-filter: blur(2px);
|
||||
border-left: 10px #FFCC00 solid;
|
||||
// border-left: 10px @app_accent_gradient solid;
|
||||
box-shadow: -2px 2px 1px 0 rgba(51, 51, 51, 0.13);
|
||||
color: rgb(102, 102, 102);
|
||||
}
|
||||
|
||||
@ -76,7 +72,7 @@
|
||||
cursor: pointer;
|
||||
|
||||
img{
|
||||
margin: 15px 0 0 0;
|
||||
margin: 15px 0 0 22px;
|
||||
max-height: 70px;
|
||||
height: 5vh;
|
||||
width: 5vh;
|
||||
@ -137,7 +133,7 @@
|
||||
}
|
||||
|
||||
.ant-menu-dark .ant-menu-item a {
|
||||
color: rgb(197, 197, 197);
|
||||
color: @AppTheme_global_color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import Sider_Default from './default'
|
||||
class Sider extends React.PureComponent {
|
||||
|
||||
handleClickMenu = e => {
|
||||
router.go(e.key)
|
||||
router.go(`/${e.key}`)
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -6,11 +6,10 @@ import styles from './index.less'
|
||||
export default class Sider_Mobile extends React.PureComponent {
|
||||
|
||||
renderMenus(data){
|
||||
// filter by item with mobile support
|
||||
return data.map(e => {
|
||||
return(
|
||||
return e.mobile? (
|
||||
<antd.Menu.Item key={e.id} style={{ color: '#ffffff', fontSize: '18px' }} >{e.icon}</antd.Menu.Item>
|
||||
)
|
||||
) : null
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -272,11 +272,11 @@ export function setLocale(language) {
|
||||
export function get_value(source,key){
|
||||
if( !key || !source ) return false
|
||||
try {
|
||||
const map = source.map(item => {
|
||||
return item.id === key? item.value : null
|
||||
const find = source.find(item => {
|
||||
return item.id === key
|
||||
})
|
||||
const fr = map.filter(Boolean)
|
||||
return fr.toString()
|
||||
return find.value
|
||||
|
||||
}
|
||||
catch (error) {
|
||||
return false
|
||||
|
@ -1,2 +1,14 @@
|
||||
import { notify } from 'core/libs/interface/notify'
|
||||
import verbosity from 'core/libs/verbosity'
|
||||
|
||||
// STRINGS
|
||||
export const OVERLAY_BADPOSITION = `Invalid overlay position! Was expected "primary" or "secondary"`
|
||||
export const INTERNAL_PROCESS_FAILED = `An internal error has occurred! `
|
||||
// HANDLERS
|
||||
export const onError = {
|
||||
internal_proccess: (...rest) => {
|
||||
verbosity.error(...rest)
|
||||
notify.warn(INTERNAL_PROCESS_FAILED, ...rest)
|
||||
return false
|
||||
}
|
||||
}
|
161
src/core/libs/json_prune/index.js
Normal file
161
src/core/libs/json_prune/index.js
Normal file
@ -0,0 +1,161 @@
|
||||
// JSON.prune : a function to stringify any object without overflow
|
||||
// two additional optional parameters :
|
||||
// - the maximal depth (default : 6)
|
||||
// - the maximal length of arrays (default : 50)
|
||||
// You can also pass an "options" object.
|
||||
// examples :
|
||||
// var json = JSON.prune(window)
|
||||
// var arr = Array.apply(0,Array(1000)); var json = JSON.prune(arr, 4, 20)
|
||||
// var json = JSON.prune(window.location, {inheritedProperties:true})
|
||||
// Web site : http://dystroy.org/JSON.prune/
|
||||
// JSON.prune on github : https://github.com/Canop/JSON.prune
|
||||
// This was discussed here : http://stackoverflow.com/q/13861254/263525
|
||||
// The code is based on Douglas Crockford's code : https://github.com/douglascrockford/JSON-js/blob/master/json2.js
|
||||
// No effort was done to support old browsers. JSON.prune will fail on IE8.
|
||||
'use strict';
|
||||
|
||||
var DEFAULT_MAX_DEPTH = 6;
|
||||
var DEFAULT_ARRAY_MAX_LENGTH = 50;
|
||||
var DEFAULT_PRUNED_VALUE = '"-pruned-"';
|
||||
var seen; // Same variable used for all stringifications
|
||||
var iterator; // either forEachEnumerableOwnProperty, forEachEnumerableProperty or forEachProperty
|
||||
|
||||
// iterates on enumerable own properties (default behavior)
|
||||
var forEachEnumerableOwnProperty = function(obj, callback) {
|
||||
for (var k in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, k)) callback(k);
|
||||
}
|
||||
};
|
||||
// iterates on enumerable properties
|
||||
var forEachEnumerableProperty = function(obj, callback) {
|
||||
for (var k in obj) callback(k);
|
||||
};
|
||||
// iterates on properties, even non enumerable and inherited ones
|
||||
// This is dangerous
|
||||
var forEachProperty = function(obj, callback, excluded) {
|
||||
if (obj==null) return;
|
||||
excluded = excluded || {};
|
||||
Object.getOwnPropertyNames(obj).forEach(function(k){
|
||||
if (!excluded[k]) {
|
||||
callback(k);
|
||||
excluded[k] = true;
|
||||
}
|
||||
});
|
||||
forEachProperty(Object.getPrototypeOf(obj), callback, excluded);
|
||||
};
|
||||
|
||||
Object.defineProperty(Date.prototype, "toPrunedJSON", {value:Date.prototype.toJSON});
|
||||
|
||||
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
meta = { // table of character substitutions
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
};
|
||||
|
||||
function quote(string) {
|
||||
escapable.lastIndex = 0;
|
||||
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
|
||||
var c = meta[a];
|
||||
return typeof c === 'string'
|
||||
? c
|
||||
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||
}) + '"' : '"' + string + '"';
|
||||
}
|
||||
|
||||
|
||||
var prune = function (value, depthDecr, arrayMaxLength) {
|
||||
var prunedString = DEFAULT_PRUNED_VALUE;
|
||||
var replacer;
|
||||
if (typeof depthDecr == "object") {
|
||||
var options = depthDecr;
|
||||
depthDecr = options.depthDecr;
|
||||
arrayMaxLength = options.arrayMaxLength;
|
||||
iterator = options.iterator || forEachEnumerableOwnProperty;
|
||||
if (options.allProperties) iterator = forEachProperty;
|
||||
else if (options.inheritedProperties) iterator = forEachEnumerableProperty
|
||||
if ("prunedString" in options) {
|
||||
prunedString = options.prunedString;
|
||||
}
|
||||
if (options.replacer) {
|
||||
replacer = options.replacer;
|
||||
}
|
||||
} else {
|
||||
iterator = forEachEnumerableOwnProperty;
|
||||
}
|
||||
seen = [];
|
||||
depthDecr = depthDecr || DEFAULT_MAX_DEPTH;
|
||||
arrayMaxLength = arrayMaxLength || DEFAULT_ARRAY_MAX_LENGTH;
|
||||
function str(key, holder, depthDecr) {
|
||||
var i, k, v, length, partial, value = holder[key];
|
||||
|
||||
if (value && typeof value === 'object' && typeof value.toPrunedJSON === 'function') {
|
||||
value = value.toPrunedJSON(key);
|
||||
}
|
||||
if (value && typeof value.toJSON === 'function') {
|
||||
value = value.toJSON();
|
||||
}
|
||||
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
return quote(value);
|
||||
case 'number':
|
||||
return isFinite(value) ? String(value) : 'null';
|
||||
case 'boolean':
|
||||
case 'null':
|
||||
return String(value);
|
||||
case 'object':
|
||||
if (!value) {
|
||||
return 'null';
|
||||
}
|
||||
if (depthDecr<=0 || seen.indexOf(value)!==-1) {
|
||||
if (replacer) {
|
||||
var replacement = replacer(value, prunedString, true);
|
||||
return replacement===undefined ? undefined : ''+replacement;
|
||||
}
|
||||
return prunedString;
|
||||
}
|
||||
seen.push(value);
|
||||
partial = [];
|
||||
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
||||
length = Math.min(value.length, arrayMaxLength);
|
||||
for (i = 0; i < length; i += 1) {
|
||||
partial[i] = str(i, value, depthDecr-1) || 'null';
|
||||
}
|
||||
v = '[' + partial.join(',') + ']';
|
||||
if (replacer && value.length>arrayMaxLength) return replacer(value, v, false);
|
||||
return v;
|
||||
}
|
||||
if (value instanceof RegExp) {
|
||||
return quote(value.toString());
|
||||
}
|
||||
iterator(value, function(k) {
|
||||
try {
|
||||
v = str(k, value, depthDecr-1);
|
||||
if (v) partial.push(quote(k) + ':' + v);
|
||||
} catch (e) {
|
||||
// this try/catch due to forbidden accessors on some objects
|
||||
}
|
||||
});
|
||||
return '{' + partial.join(',') + '}';
|
||||
case 'function':
|
||||
case 'undefined':
|
||||
return replacer ? replacer(value, undefined, false) : undefined;
|
||||
}
|
||||
}
|
||||
return str('', {'': value}, depthDecr);
|
||||
};
|
||||
|
||||
prune.log = function() {
|
||||
console.log.apply(console, Array.prototype.map.call(arguments, function(v) {
|
||||
return JSON.parse(JSON.prune(v));
|
||||
}));
|
||||
};
|
||||
prune.forEachProperty = forEachProperty; // you might want to also assign it to Object.forEachProperty
|
||||
|
||||
export default prune
|
@ -1,7 +1,6 @@
|
||||
import { defaults, app_config } from 'config'
|
||||
import { get_value } from 'core'
|
||||
|
||||
|
||||
export function parseLocalStorage(){
|
||||
const a = localStorage.getItem(app_config.app_settings_storage)
|
||||
try {
|
||||
@ -10,8 +9,15 @@ export function parseLocalStorage(){
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
export function newSetting(key, value) {
|
||||
let setting = {}
|
||||
setting.id = key
|
||||
setting.value = value
|
||||
return [setting]
|
||||
}
|
||||
|
||||
export function settingValue(key){
|
||||
export const settings = {
|
||||
get: (key) => {
|
||||
let tmp = [];
|
||||
|
||||
const keys = Object.keys(defaults)
|
||||
@ -19,8 +25,19 @@ export function settingValue(key){
|
||||
const length = keys.length
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const storagedValue = get_value(parseLocalStorage(), keys[i])
|
||||
tmp[keys[i]] = (storagedValue? storagedValue : values[i])
|
||||
if(parseLocalStorage()){
|
||||
const storagedValue = parseLocalStorage().find(item => {
|
||||
return item.id === keys[i]
|
||||
})
|
||||
if (typeof(storagedValue) == 'undefined') {
|
||||
tmp[keys[i]] = values[i]
|
||||
}else{
|
||||
tmp[keys[i]] = storagedValue.value
|
||||
}
|
||||
}
|
||||
else{
|
||||
tmp[keys[i]] = values[i]
|
||||
}
|
||||
}
|
||||
|
||||
if (key) {
|
||||
@ -28,23 +45,35 @@ export function settingValue(key){
|
||||
}
|
||||
|
||||
return tmp
|
||||
}
|
||||
|
||||
export const storage = {
|
||||
get: (key) => {
|
||||
return settingValue(key)
|
||||
},
|
||||
set: (key, value) => {
|
||||
const storaged = parseLocalStorage()
|
||||
const updated = storaged.map(element => {
|
||||
let tmp
|
||||
let data = parseLocalStorage()
|
||||
|
||||
if (data) {
|
||||
const finded = data.find(element => {
|
||||
return element.id === key
|
||||
})
|
||||
if (!finded) {
|
||||
const parsed = data.concat(newSetting(key, value))
|
||||
tmp = parsed
|
||||
} else {
|
||||
const updated = data.map(element => {
|
||||
return element.id === key? Object.assign(element, { value: value }) : element
|
||||
});
|
||||
})
|
||||
tmp = updated
|
||||
}
|
||||
}else{
|
||||
tmp = newSetting(key, value)
|
||||
}
|
||||
data = tmp
|
||||
try {
|
||||
localStorage.setItem( app_config.app_settings_storage, JSON.stringify(updated) )
|
||||
localStorage.setItem( app_config.app_settings_storage, JSON.stringify(data) )
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default settingValue
|
||||
export default (e) => settings.get(e)
|
237
src/core/libs/style/index.js
Normal file
237
src/core/libs/style/index.js
Normal file
@ -0,0 +1,237 @@
|
||||
import store from 'store';
|
||||
import { app_config } from 'config';
|
||||
import verbosity from 'core/libs/verbosity'
|
||||
import * as errorHandlers from 'core/libs/errorhandler'
|
||||
import { negate } from 'lodash';
|
||||
|
||||
const { appTheme_desiredContrast, appTheme_container } = app_config
|
||||
|
||||
export const theme = {
|
||||
get: (key) => {
|
||||
if(!localStorage.getItem(appTheme_container)) return false
|
||||
const raw = store.get(appTheme_container)
|
||||
let container = []
|
||||
if (raw) {
|
||||
raw.forEach((e)=>{
|
||||
container[e.key] = e.value
|
||||
})
|
||||
return container
|
||||
}
|
||||
return null
|
||||
},
|
||||
set: (data) => {
|
||||
if (!data || data.length > 2) return false
|
||||
try {
|
||||
let mix = []
|
||||
const obj = Object.entries(data)
|
||||
obj.forEach((e) => {
|
||||
mix.push({key: e[0], value: e[1]})
|
||||
})
|
||||
return store.set(appTheme_container, mix)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
return false
|
||||
}
|
||||
},
|
||||
raw: () => {
|
||||
return store.get(appTheme_container)
|
||||
}
|
||||
}
|
||||
|
||||
export function get_style_rule_value(selector, style)
|
||||
{
|
||||
const selector_lowercase = selector.toLowerCase();
|
||||
const selector_parsed = selector_lowercase.substr(0,1)==='.' ? selector_lowercase.substr(1) : '.'+selector_lowercase;
|
||||
|
||||
for (let i = 0; i < document.styleSheets.length; i++)
|
||||
{
|
||||
let styleSheet = document.styleSheets[i];
|
||||
let rules = styleSheet.cssRules ? styleSheet.cssRules : styleSheet.rules;
|
||||
|
||||
for (var j = 0; j < rules.length; j++)
|
||||
{
|
||||
if (rules[j].selectorText)
|
||||
{
|
||||
var check = rules[j].selectorText.toLowerCase();
|
||||
switch (check)
|
||||
{
|
||||
case selector_lowercase :
|
||||
case selector_parsed : return rules[j].style[style];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getOptimalOpacityFromIMG(payload, callback) {
|
||||
const { textColor, overlayColor, img } = payload;
|
||||
|
||||
verbosity.debug(payload)
|
||||
let canvas = document.createElement('canvas');
|
||||
let image = new Image();
|
||||
|
||||
image.src = img
|
||||
image.setAttribute('crossOrigin', '');
|
||||
image.onload = () =>{
|
||||
const imagePixelColors = getImagePixelColorsUsingCanvas(canvas, image);
|
||||
if(imagePixelColors){
|
||||
const worstContrastColorInImage = getWorstContrastColorInImage(textColor, imagePixelColors);
|
||||
const optimalOpacity = findOptimalOverlayOpacity(textColor, overlayColor, worstContrastColorInImage, appTheme_desiredContrast);
|
||||
return callback(optimalOpacity)
|
||||
}else{
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function getImagePixelColorsUsingCanvas(canvas, image) {
|
||||
let imagePixelColors = null;
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
canvas.height = getCanvasHeightToMatchImageProportions(canvas, image);
|
||||
|
||||
const sourceImageCoordinates = [0, 0, image.width, image.height];
|
||||
const destinationCanvasCoordinates = [0, 0, canvas.width, canvas.height];
|
||||
|
||||
ctx.drawImage(
|
||||
image,
|
||||
...sourceImageCoordinates,
|
||||
...destinationCanvasCoordinates
|
||||
);
|
||||
|
||||
// Remember getImageData only works for same-origin or cross-origin-enabled images.
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more info.
|
||||
try {
|
||||
imagePixelColors = ctx.getImageData(...destinationCanvasCoordinates);
|
||||
} catch (error) {
|
||||
return errorHandlers.onError.internal_proccess(error)
|
||||
}
|
||||
|
||||
if (imagePixelColors) {
|
||||
return imagePixelColors
|
||||
}
|
||||
}
|
||||
|
||||
export function getCanvasHeightToMatchImageProportions(canvas, image) {
|
||||
return (image.height / image.width) * canvas.width;
|
||||
}
|
||||
|
||||
export function getWorstContrastColorInImage(textColor, imagePixelColors) {
|
||||
let worstContrastColorInImage;
|
||||
let worstContrast = Infinity;
|
||||
|
||||
for (let i = 0; i < imagePixelColors.data.length; i += 4) {
|
||||
let pixelColor = {
|
||||
r: imagePixelColors.data[i],
|
||||
g: imagePixelColors.data[i + 1],
|
||||
b: imagePixelColors.data[i + 2],
|
||||
};
|
||||
|
||||
let contrast = getContrast(textColor, pixelColor);
|
||||
if(contrast < worstContrast) {
|
||||
worstContrast = contrast;
|
||||
worstContrastColorInImage = pixelColor;
|
||||
}
|
||||
}
|
||||
return worstContrastColorInImage;
|
||||
}
|
||||
|
||||
export function getContrast(color1, color2) {
|
||||
const color1_luminance = getLuminance(color1);
|
||||
const color2_luminance = getLuminance(color2);
|
||||
|
||||
const lighterColorLuminance = Math.max(color1_luminance, color2_luminance);
|
||||
const darkerColorLuminance = Math.min(color1_luminance, color2_luminance);
|
||||
|
||||
const contrast = (lighterColorLuminance + 0.05) / (darkerColorLuminance + 0.05);
|
||||
return contrast;
|
||||
}
|
||||
|
||||
export function getLuminance({r,g,b}) {
|
||||
return (0.2126 * getLinearRGB(r) + 0.7152 * getLinearRGB(g) + 0.0722 * getLinearRGB(b));
|
||||
}
|
||||
|
||||
export function getLinearRGB(primaryColor_8bit) {
|
||||
// First convert from 8-bit rbg (0-255) to standard RGB (0-1)
|
||||
const primaryColor_sRGB = convert_8bit_RGB_to_standard_RGB(primaryColor_8bit);
|
||||
|
||||
// Then convert from sRGB to linear RGB so we can use it to calculate luminance
|
||||
const primaryColor_RGB_linear = convert_standard_RGB_to_linear_RGB(primaryColor_sRGB);
|
||||
|
||||
return primaryColor_RGB_linear;
|
||||
}
|
||||
|
||||
export function convert_8bit_RGB_to_standard_RGB(primaryColor_8bit) {
|
||||
return primaryColor_8bit / 255;
|
||||
}
|
||||
|
||||
export function convert_standard_RGB_to_linear_RGB(primaryColor_sRGB) {
|
||||
const primaryColor_linear = primaryColor_sRGB < 0.03928 ?
|
||||
primaryColor_sRGB/12.92 :
|
||||
Math.pow((primaryColor_sRGB + 0.055) / 1.055, 2.4);
|
||||
return primaryColor_linear;
|
||||
}
|
||||
|
||||
export function getTextContrastWithImagePlusOverlay({textColor, overlayColor, imagePixelColor, overlayOpacity}) {
|
||||
const colorOfImagePixelPlusOverlay = mixColors(imagePixelColor, overlayColor, overlayOpacity);
|
||||
const contrast = getContrast(textColor, colorOfImagePixelPlusOverlay);
|
||||
return contrast;
|
||||
}
|
||||
|
||||
export function mixColors(baseColor, overlayColor, overlayOpacity) {
|
||||
const mixedColor = {
|
||||
r: baseColor.r + (overlayColor.r - baseColor.r) * overlayOpacity,
|
||||
g: baseColor.g + (overlayColor.g - baseColor.g) * overlayOpacity,
|
||||
b: baseColor.b + (overlayColor.b - baseColor.b) * overlayOpacity,
|
||||
}
|
||||
return mixedColor;
|
||||
}
|
||||
|
||||
export function findOptimalOverlayOpacity(textColor, overlayColor, worstContrastColorInImage, appTheme_desiredContrast) {
|
||||
const opacityGuessRange = {
|
||||
lowerBound: 0,
|
||||
midpoint: 0.5,
|
||||
upperBound: 1,
|
||||
};
|
||||
|
||||
let numberOfGuesses = 0;
|
||||
const maxGuesses = 8;
|
||||
const opacityLimit = 0.99;
|
||||
|
||||
while (numberOfGuesses < maxGuesses) {
|
||||
numberOfGuesses++;
|
||||
const currentGuess = opacityGuessRange.midpoint;
|
||||
|
||||
const contrastOfGuess = getTextContrastWithImagePlusOverlay({
|
||||
textColor,
|
||||
overlayColor,
|
||||
imagePixelColor: worstContrastColorInImage,
|
||||
overlayOpacity: currentGuess,
|
||||
});
|
||||
|
||||
const isGuessTooLow = contrastOfGuess < appTheme_desiredContrast;
|
||||
const isGuessTooHigh = contrastOfGuess > appTheme_desiredContrast;
|
||||
|
||||
if (isGuessTooLow) {
|
||||
opacityGuessRange.lowerBound = currentGuess;
|
||||
}
|
||||
else if (isGuessTooHigh) {
|
||||
opacityGuessRange.upperBound = currentGuess;
|
||||
}
|
||||
|
||||
const newMidpoint = ((opacityGuessRange.upperBound - opacityGuessRange.lowerBound) / 2) + opacityGuessRange.lowerBound;
|
||||
opacityGuessRange.midpoint = newMidpoint;
|
||||
}
|
||||
|
||||
const optimalOpacity = opacityGuessRange.midpoint;
|
||||
|
||||
if (optimalOpacity > opacityLimit) {
|
||||
return opacityLimit;
|
||||
}
|
||||
|
||||
return optimalOpacity;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { storage } from 'core/libs/settings'
|
||||
import settings from 'core/libs/settings'
|
||||
import stackTrace from 'stack-trace'
|
||||
// import path from 'path'
|
||||
const verbosity_enabled = storage.get('verbosity')
|
||||
const verbosity_enabled = settings('verbosity')
|
||||
|
||||
const verbosity = {
|
||||
log: (...cont) => {
|
||||
|
@ -12,6 +12,7 @@ import store from 'store'
|
||||
import classnames from 'classnames'
|
||||
|
||||
import { app_config } from 'config'
|
||||
import { theme } from 'core/libs/style'
|
||||
import * as antd from 'antd'
|
||||
|
||||
import styles from './PrimaryLayout.less'
|
||||
@ -23,12 +24,13 @@ const { Sider, Control, Overlay } = MyLayout
|
||||
@connect(({ app, loading }) => ({ app, loading }))
|
||||
class PrimaryLayout extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
window.PrimaryComponent = this
|
||||
super(props);
|
||||
this.state = {
|
||||
collapsed: app_config.default_collapse_sider ? true : false,
|
||||
isMobile: false,
|
||||
}
|
||||
},
|
||||
window.PrimaryComponent = this;
|
||||
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@ -52,10 +54,25 @@ class PrimaryLayout extends React.PureComponent {
|
||||
store.set('collapsed', !fromStore)
|
||||
}
|
||||
|
||||
Swapper = {
|
||||
|
||||
renderThemeComponents() {
|
||||
const currentTheme = theme.get()
|
||||
if (!currentTheme) return false
|
||||
if (currentTheme.backgroundImage) {
|
||||
return currentTheme.backgroundImage.active? <div style={{
|
||||
backgroundImage: `url(${currentTheme.backgroundImage.src})`,
|
||||
transition: "all 150ms linear",
|
||||
position: 'absolute',
|
||||
width: '100vw',
|
||||
height: '100vh',
|
||||
backgroundRepeat: "repeat-x",
|
||||
backgroundSize: "cover",
|
||||
backgroundPositionY: "center",
|
||||
overflow: "hidden",
|
||||
opacity: currentTheme.backgroundImage.opacity
|
||||
}} /> : null
|
||||
}
|
||||
|
||||
}
|
||||
render() {
|
||||
const { location, dispatch, children } = this.props
|
||||
const { collapsed, isMobile } = this.state
|
||||
@ -77,6 +94,8 @@ class PrimaryLayout extends React.PureComponent {
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Control />
|
||||
{this.renderThemeComponents()}
|
||||
<antd.Layout id="primaryLayout" className={classnames(styles.primary_layout, {[styles.mobile]: isMobile})}>
|
||||
<Sider {...SiderProps} />
|
||||
<div className={styles.primary_layout_container}>
|
||||
|
@ -26,7 +26,8 @@ export default {
|
||||
controlActive: false,
|
||||
feedOutdated: false,
|
||||
|
||||
app_settings: store.get('app_settings'),
|
||||
app_settings: store.get(app_config.app_settings_storage),
|
||||
app_theme: store.get(app_config.appTheme_container),
|
||||
notifications: [],
|
||||
locationQuery: {},
|
||||
|
||||
@ -52,7 +53,7 @@ export default {
|
||||
|
||||
cancelRequest.forEach((value, key) => {
|
||||
if (value.pathname !== window.location.pathname) {
|
||||
value.cancel(CANCEL_REQUEST_MESSAGE);
|
||||
value.cancel('cancel request');
|
||||
cancelRequest.delete(key);
|
||||
}
|
||||
});
|
||||
@ -113,6 +114,25 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
*updateTheme({payload}, {call, put, select}){
|
||||
if (!payload) return false;
|
||||
let tmp = []
|
||||
|
||||
const keys = Object.keys(payload)
|
||||
const values = Object.values(payload)
|
||||
const lenght = keys.length
|
||||
|
||||
for (let i = 0; i < lenght; i++) {
|
||||
let obj = {}
|
||||
obj.key = keys[i]
|
||||
obj.value = values[i]
|
||||
|
||||
tmp[i] = obj
|
||||
}
|
||||
|
||||
return yield put({ type: 'handleUpdateTheme', payload: tmp });
|
||||
|
||||
},
|
||||
},
|
||||
reducers: {
|
||||
updateState(state, { payload }) {
|
||||
@ -131,6 +151,12 @@ export default {
|
||||
state.notifications = [];
|
||||
},
|
||||
|
||||
handleUpdateTheme(state, { payload }) {
|
||||
verbosity.debug(payload)
|
||||
store.set(app_config.appTheme_container, payload);
|
||||
state.app_theme = payload
|
||||
},
|
||||
|
||||
disconnectServices(state) {
|
||||
state.service_valid = false;
|
||||
state.session_valid = false;
|
||||
|
@ -14,7 +14,6 @@ import {
|
||||
import classnames from 'classnames';
|
||||
import { CloseOutlined } from '@ant-design/icons';
|
||||
import endpoints_list from 'config/endpoints';
|
||||
import { Page } from 'components';
|
||||
|
||||
import styles from './index.less';
|
||||
|
||||
@ -171,7 +170,7 @@ class RequestPage extends React.Component {
|
||||
const { result, url, method, ParamsKeys, BodyKeys, visible } = this.state;
|
||||
|
||||
return (
|
||||
<Page inner>
|
||||
<div>
|
||||
<Row>
|
||||
<Col lg={8} md={24}>
|
||||
<List
|
||||
@ -343,7 +342,7 @@ class RequestPage extends React.Component {
|
||||
<div className={styles.result}>{result}</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Page>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
79
src/pages/debug/theme.js
Normal file
79
src/pages/debug/theme.js
Normal file
@ -0,0 +1,79 @@
|
||||
import React from 'react'
|
||||
import * as antd from 'antd'
|
||||
import * as themeLIB from 'core/libs/style'
|
||||
|
||||
function getBase64(img, callback) {
|
||||
const reader = new FileReader()
|
||||
reader.addEventListener('load', () => callback(reader.result))
|
||||
reader.readAsDataURL(img)
|
||||
}
|
||||
|
||||
export default class themedebug extends React.PureComponent {
|
||||
state = {
|
||||
textColor: {r: '255', g: '255', b: '255'},
|
||||
overlayColor: {r: '0', g: '0', b: '0'},
|
||||
|
||||
optimal: null,
|
||||
file: null,
|
||||
fileURL: null,
|
||||
}
|
||||
ToogleUpload() {
|
||||
this.setState({ uploader: !this.state.uploader })
|
||||
}
|
||||
handleDeleteFile = () => {
|
||||
this.setState({ fileURL: null })
|
||||
}
|
||||
handleFileUpload = info => {
|
||||
if (info.file.status === 'uploading') {
|
||||
this.setState({ loading: true })
|
||||
return
|
||||
}
|
||||
if (info.file.status === 'done') {
|
||||
this.setState({ file: info.file.originFileObj, uploader: false })
|
||||
getBase64(info.file.originFileObj, fileURL => {
|
||||
this.setState({ fileURL, loading: false })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleGetOptimal() {
|
||||
const optimal = themeLIB.getOptimalOpacityFromIMG({ textColor: this.state.textColor, overlayColor: this.state.overlayColor, img: this.state.fileURL })
|
||||
this.setState({ optimal: optimal })
|
||||
}
|
||||
|
||||
schemeToRGB(values) {
|
||||
return `rgb(${values.r}, ${values.g}, ${values.b})`
|
||||
}
|
||||
|
||||
render(){
|
||||
|
||||
return(
|
||||
<div style={{ wordBreak: 'keep-all' }}>
|
||||
<antd.Button onClick={() => this.handleGetOptimal()}> Get OPACITY </antd.Button>
|
||||
<antd.Upload
|
||||
multiple="false"
|
||||
onChange={this.handleFileUpload}
|
||||
>
|
||||
<antd.Button>
|
||||
Click to Upload
|
||||
</antd.Button>
|
||||
</antd.Upload>
|
||||
<div>
|
||||
{JSON.stringify(this.state.file)}<br/><br/>
|
||||
textColor:{JSON.stringify(this.state.textColor)}<br/><br/>
|
||||
overlayColor:{JSON.stringify(this.state.overlayColor)}<br/><br/>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div style={{ position: 'absolute', backgroundColor: this.schemeToRGB(this.state.overlayColor) , display: 'flex', width: '500px', height: '500px' }}>
|
||||
<h2 style={{ position: 'absolute', zIndex: '10', color: this.schemeToRGB(this.state.textColor) }}>Sample text</h2>
|
||||
<img style={{ position: 'absolute',opacity: this.state.optimal, zIndex: '9', width: '500px' }} src={this.state.fileURL} />
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -1,30 +1,29 @@
|
||||
import React, { Component, Fragment } from 'react'
|
||||
import { List, Switch, Button, notification, InputNumber } from 'antd'
|
||||
import ListSettings from 'globals/settings'
|
||||
import ControlBar from 'components/layout/ControlBar'
|
||||
import { control } from 'components/layout/ControlBar'
|
||||
|
||||
import verbosity from 'core/libs/verbosity'
|
||||
import * as Icons from 'components/Icons'
|
||||
import { settings, newSetting } from 'core/libs/settings'
|
||||
|
||||
class Base extends Component {
|
||||
constructor(props) {
|
||||
super(props),
|
||||
(this.state = {
|
||||
SettingRepo: ListSettings,
|
||||
forSave: false,
|
||||
})
|
||||
super(props);
|
||||
this.state = {
|
||||
list: ListSettings,
|
||||
};
|
||||
}
|
||||
|
||||
rendersets = item => {
|
||||
let e = item.type
|
||||
switch (e) {
|
||||
renderSetting = item => {
|
||||
switch (item.type) {
|
||||
case 'switch':
|
||||
return (
|
||||
<Switch
|
||||
checkedChildren={'Enabled'}
|
||||
unCheckedChildren={'Disabled'}
|
||||
checked={item.value ? true : false}
|
||||
onChange={() => this.onChangeSwitch(item)}
|
||||
checked={settings.get(item.id)}
|
||||
onChange={() => this.onChange(item)}
|
||||
/>
|
||||
)
|
||||
case 'numeric':
|
||||
@ -41,29 +40,6 @@ class Base extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
SettingRender = data => {
|
||||
try {
|
||||
return (
|
||||
<div>
|
||||
<List
|
||||
itemLayout="horizontal"
|
||||
dataSource={data}
|
||||
renderItem={item => (
|
||||
<List.Item actions={item.actions} key={item.SettingID}>
|
||||
<List.Item.Meta
|
||||
title={item.title}
|
||||
description={item.description}
|
||||
/>
|
||||
{this.rendersets(item)}
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
} catch (err) {
|
||||
return verbosity.log(err)
|
||||
}
|
||||
}
|
||||
handleControlBar() {
|
||||
const ListControls = [
|
||||
<div key={Math.random()}>
|
||||
@ -76,7 +52,7 @@ class Base extends Component {
|
||||
</Button>
|
||||
</div>,
|
||||
]
|
||||
ControlBar.set(ListControls)
|
||||
control.set(ListControls)
|
||||
}
|
||||
|
||||
saveChanges() {
|
||||
@ -87,39 +63,44 @@ class Base extends Component {
|
||||
description:
|
||||
'The configuration has been saved, it may for some configuration to make changes you need to reload the application',
|
||||
})
|
||||
setTimeout(app._app.refresh(), 1000)
|
||||
ControlBar.close()
|
||||
control.close()
|
||||
}
|
||||
|
||||
onChangeSwitch(item) {
|
||||
onChange(item) {
|
||||
try {
|
||||
this.handleControlBar()
|
||||
const to = !item.value
|
||||
const updatedValue = [...this.state.SettingRepo].map(ita =>
|
||||
ita === item ? Object.assign(ita, { value: to }) : ita
|
||||
)
|
||||
this.setState({ SettingRepo: updatedValue, forSave: true })
|
||||
verbosity.log(`Changing ${item.SettingID} to value ${to}`)
|
||||
switch (item.type) {
|
||||
case 'switch': {
|
||||
item.to = !settings.get(item.id)
|
||||
verbosity.debug(`Changing setting (${item.id}: ${settings.get(item.id)}) => ${item.to}`)
|
||||
settings.set(item.id, item.to)
|
||||
this.handleChange(item)
|
||||
|
||||
}
|
||||
case 'numeric': {
|
||||
|
||||
}
|
||||
default: {
|
||||
return null
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
onChangeNumeric(value, item) {
|
||||
this.HandleChangeNumeric(value)
|
||||
}
|
||||
HandleChangeNumeric(item, value) {
|
||||
|
||||
|
||||
handleChange(item) {
|
||||
try {
|
||||
this.handleControlBar()
|
||||
console.log(item.SettingID, value)
|
||||
const updatedValue = [...this.state.SettingRepo].map(ita =>
|
||||
ita === item ? Object.assign(ita, { value: value }) : ita
|
||||
const updatedValue = this.state.list.map(element =>
|
||||
element.id === item.id ? Object.assign(element, { value: item.to }) : element
|
||||
)
|
||||
this.setState({ SettingRepo: updatedValue, forSave: true })
|
||||
verbosity.log(`Changing ${item.SettingID} to value ${to}`)
|
||||
this.setState({ list: updatedValue})
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Fragment>
|
||||
@ -127,7 +108,19 @@ class Base extends Component {
|
||||
<h1>
|
||||
<Icons.PullRequestOutlined /> Behaviors
|
||||
</h1>
|
||||
{this.SettingRender(this.state.SettingRepo)}
|
||||
<List
|
||||
itemLayout="horizontal"
|
||||
dataSource={this.state.list}
|
||||
renderItem={item => (
|
||||
<List.Item actions={item.actions} key={item.id}>
|
||||
<List.Item.Meta
|
||||
title={item.title}
|
||||
description={item.description}
|
||||
/>
|
||||
{this.renderSetting(item)}
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</Fragment>
|
||||
)
|
||||
|
@ -1,12 +1,35 @@
|
||||
import React from 'react'
|
||||
import * as Feather from 'feather-reactjs'
|
||||
import * as Icons from 'components/Icons'
|
||||
import * as antd from 'antd'
|
||||
import themeSettings from 'globals/theme_settings'
|
||||
import {connect} from 'umi'
|
||||
import styles from './index.less'
|
||||
import json_prune from 'core/libs/json_prune'
|
||||
|
||||
|
||||
import { SketchPicker } from 'react-color';
|
||||
import { theme, getOptimalOpacityFromIMG, get_style_rule_value } from 'core/libs/style'
|
||||
|
||||
import ColorThief from 'colorthief/dist/color-thief'
|
||||
var colorThief = new ColorThief();
|
||||
|
||||
function getBase64(img, callback) {
|
||||
const reader = new FileReader()
|
||||
reader.addEventListener('load', () => callback(reader.result))
|
||||
reader.readAsDataURL(img)
|
||||
}
|
||||
|
||||
function toDataUrl(url, callback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onload = function() {
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = function() {
|
||||
callback(reader.result);
|
||||
}
|
||||
reader.readAsDataURL(xhr.response);
|
||||
};
|
||||
xhr.open('GET', url);
|
||||
xhr.responseType = 'blob';
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
class BackgroundColor extends React.Component{
|
||||
state = {
|
||||
@ -29,30 +52,219 @@ class BackgroundColor extends React.Component{
|
||||
}
|
||||
}
|
||||
|
||||
@connect(({ app }) => ({ app }))
|
||||
class BackgroundImage extends React.Component{
|
||||
state = {
|
||||
results: []
|
||||
customURL: '',
|
||||
fileURL: null,
|
||||
processing: null,
|
||||
model: { active: false, opacity: null, src: null }
|
||||
}
|
||||
|
||||
search(key){
|
||||
if (!key) return false
|
||||
app.api_unsplash.search(key, (res) =>{
|
||||
console.log(res)
|
||||
this.setState({ results: res })
|
||||
handleFileUpload = info => {
|
||||
if (info.file.status === 'uploading') {
|
||||
return this.setState({ processing: false })
|
||||
}
|
||||
if (info.file.status === 'done') {
|
||||
this.setState({ processing: true })
|
||||
getBase64(info.file.originFileObj, fileURL => {
|
||||
this.setState({ fileURL: fileURL })
|
||||
this.proccessBackground(fileURL)
|
||||
})
|
||||
}
|
||||
returnString(url){
|
||||
this.props.selectImg(`url(${url})`)
|
||||
}
|
||||
|
||||
handleCustomURL(url){
|
||||
this.setState({ processing: true })
|
||||
this.setState({ fileURL: url })
|
||||
|
||||
toDataUrl(url, fileURL => {
|
||||
this.proccessBackground(fileURL)
|
||||
})
|
||||
}
|
||||
|
||||
handleUpdate(payload){
|
||||
if (!payload) {
|
||||
payload = this.state.model
|
||||
}
|
||||
this.setState({ model: payload, processing: false })
|
||||
this.props.dispatch({
|
||||
type: 'app/updateTheme',
|
||||
payload: { backgroundImage: payload }
|
||||
});
|
||||
}
|
||||
|
||||
handleErase(){
|
||||
this.handleUpdate({})
|
||||
}
|
||||
|
||||
handleExport(){
|
||||
const string = JSON.stringify(this.state.model)
|
||||
const exportCodeRender = () => {
|
||||
if(string.length > 500){
|
||||
return <div style={{ textAlign: 'center', width: '100%', padding: '30px 0 30px 0' }}>
|
||||
<Icons.HardDrive style={{ fontSize: '45px', margin: '0' }} />
|
||||
<h4>Hey, this file is too much large!</h4>
|
||||
<span>So it couldn't be displayed.</span>
|
||||
</div>
|
||||
}
|
||||
return <div>
|
||||
{string}
|
||||
</div>
|
||||
}
|
||||
antd.Modal.confirm({
|
||||
title: <div><Icons.Code /> Your export <antd.Tag> JSON </antd.Tag></div>,
|
||||
icon: null,
|
||||
onOk: () => {
|
||||
let tmp = document.createElement('a')
|
||||
tmp.href = `data:text/json;charset=utf-8,${encodeURIComponent(string)}`
|
||||
tmp.download="export.json"
|
||||
tmp.click()
|
||||
},
|
||||
okText: <><Icons.Download />Download as File</> ,
|
||||
cancelText: "Done",
|
||||
content: exportCodeRender(),
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
proccessBackground(data){
|
||||
getOptimalOpacityFromIMG({textColor: this.state.textColor, overlayColor: this.state.overlayColor, img: data}, (res) => {
|
||||
this.handleUpdate({active: true, src: this.state.fileURL, opacity: res})
|
||||
})
|
||||
}
|
||||
|
||||
schemeToRGB(values){
|
||||
const scheme = values || { r: '0', g: '0', b: '0' }
|
||||
const r = scheme.r || '0'
|
||||
const g = scheme.g || '0'
|
||||
const b = scheme.b || '0'
|
||||
return `rgb(${r}, ${g}, ${b})`
|
||||
}
|
||||
|
||||
rgbToScheme(rgb){
|
||||
const values = rgb.replace(/[^\d,]/g, '').split(',');
|
||||
return {r: values[0], g: values[1], b: values[2]}
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
const storaged = theme.get()["backgroundImage"]
|
||||
if(storaged){
|
||||
this.setState({ model: storaged })
|
||||
}
|
||||
|
||||
let textColor = this.rgbToScheme(get_style_rule_value('#root', 'color'))
|
||||
let overlayColor = this.rgbToScheme(get_style_rule_value('#root', 'backgroundColor'))
|
||||
|
||||
this.setState({
|
||||
textColor: textColor,
|
||||
overlayColor: overlayColor
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
render(){
|
||||
const promiseState = async state => new Promise(resolve => this.setState(state, resolve));
|
||||
|
||||
const PreviewModel = () => {
|
||||
return(
|
||||
<div>
|
||||
<h3><Icons.Layout /> Preview</h3>
|
||||
{ this.state.model.src? <div className={styles.background_image_preview} style={{ backgroundColor: this.schemeToRGB(this.state.overlayColor) }}>
|
||||
<div style={{ color: `${this.schemeToRGB(this.state.textColor)}!important` }} className={styles.text_wrapper}>
|
||||
<h1 style={{ color: this.schemeToRGB(this.state.textColor) }}>Sample text</h1>
|
||||
<h2 style={{ color: this.schemeToRGB(this.state.textColor) }}>Sample text</h2>
|
||||
<h3 style={{ color: this.schemeToRGB(this.state.accentColor) }}>Sample text</h3>
|
||||
<h4 style={{ color: this.schemeToRGB(this.state.accentColor) }}>Sample text</h4>
|
||||
<p style={{ color: this.schemeToRGB(this.state.textColor) }}>Some text here</p>
|
||||
<p style={{ color: this.schemeToRGB(this.state.accentColor) }}>Some text here</p>
|
||||
|
||||
</div>
|
||||
<img style={{ opacity: this.state.model.opacity }} src={this.state.model.src} />
|
||||
</div> : <h3 style={{ textAlign: 'center' }} > No Background </h3> }
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3> <Feather.Image /> Upload </h3>
|
||||
<div>
|
||||
<h2><Icons.Image/> Background Image</h2>
|
||||
</div>
|
||||
<antd.Divider type="horizontal" dashed />
|
||||
<div className={styles.background_image_controls} >
|
||||
<div>
|
||||
<h4><Icons.Eye />Enabled</h4>
|
||||
<antd.Switch
|
||||
checkedChildren="Enabled"
|
||||
unCheckedChildren="Disabled"
|
||||
loading={this.state.processing}
|
||||
onChange={(e) => {
|
||||
promiseState(prevState => ({ model: { ...prevState.model, active: e }})).then(() => this.handleUpdate())
|
||||
}}
|
||||
checked={this.state.model.active}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
<h4><Icons.Layers />Opacity</h4>
|
||||
<antd.Slider disabled={!this.state.model.src} onChange={(e) => {
|
||||
this.setState(
|
||||
prevState => ({
|
||||
model: {
|
||||
...prevState.model,
|
||||
opacity: e/100
|
||||
}
|
||||
})
|
||||
)
|
||||
}} onAfterChange={() => this.handleUpdate()} value={this.state.model.opacity*100} />
|
||||
</div>
|
||||
<div>
|
||||
<h4><Icons.Code />Export Code</h4>
|
||||
<antd.Button disabled={!this.state.model.src} size="small" onClick={() => this.handleExport()}> Export </antd.Button>
|
||||
</div>
|
||||
<div>
|
||||
<h4><Icons.Trash />Erase</h4>
|
||||
<antd.Popconfirm disabled={!this.state.model.src} placement="topLeft" title="Are you sure?" onConfirm={() => this.handleErase()} okText="Yes" cancelText="No">
|
||||
<antd.Button disabled={!this.state.model.src} size="small" type="primary" danger > Delete </antd.Button>
|
||||
</antd.Popconfirm>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<antd.Divider type="horizontal" dashed />
|
||||
<PreviewModel />
|
||||
<antd.Divider type="horizontal" dashed />
|
||||
|
||||
<h3> Unsplash </h3>
|
||||
|
||||
<div>
|
||||
<h3><Icons.Upload /> Upload </h3>
|
||||
<div className={styles.background_image_uploader} >
|
||||
<div>
|
||||
Upload from your files <br/>
|
||||
<antd.Upload onChange={this.handleFileUpload}>
|
||||
<antd.Button icon={<Icons.Upload type="primary" style={{ margin: '5px 0 0 0' }} />} />
|
||||
</antd.Upload>
|
||||
</div>
|
||||
<div>
|
||||
<h3>Or</h3>
|
||||
</div>
|
||||
<div>
|
||||
Upload from URL
|
||||
<antd.Input onPressEnter={() => this.handleCustomURL(this.state.customURL)} onChange={e => this.setState({ customURL: e.target.value })} value={this.state.customURL} placeholder="http://example.com/my_coolest_image.jpg" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.state.processing? <h4><Icons.LoadingOutlined spin /> Processing image ... </h4> : null}
|
||||
{this.state.params? JSON.stringify(this.state.params) : null}
|
||||
</div>
|
||||
|
||||
<antd.Divider type="horizontal" dashed />
|
||||
|
||||
{/* <h3><Icons.Unsplash style={{ marginRight: "10px", verticalAlign: "-0.125em", width: "1em", height: "1em" }} /> Unsplash </h3>
|
||||
<antd.Input.Search onSearch={value => this.search(value)} />
|
||||
<antd.List itemLayout="vertical" dataSource={this.state.results} renderItem={item => ( <antd.List.Item> <img onClick={() => this.returnString(item.urls.full)} src={item.urls.small} /> </antd.List.Item>) }/>
|
||||
<antd.List itemLayout="vertical" dataSource={this.state.results} renderItem={item => ( <antd.List.Item> <img onClick={() => this.returnString(item.urls.full)} src={item.urls.small} /> </antd.List.Item>) }/> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -62,96 +274,9 @@ export default class ThemeSettings extends React.PureComponent{
|
||||
state = {
|
||||
helper_visible: false,
|
||||
helper_fragment: null,
|
||||
style: [],
|
||||
style: theme.get(),
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.decodeData()
|
||||
}
|
||||
|
||||
decodeData(){
|
||||
const storaged = app.app_theme.getString()
|
||||
try {
|
||||
if (storaged) {
|
||||
this.decode(storaged, (res) => {
|
||||
this.setState({ style: res })
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
encode(data, callback){
|
||||
if (!data) return false
|
||||
try {
|
||||
let mix = []
|
||||
const obj = Object.entries(data)
|
||||
obj.forEach((e) => {
|
||||
mix.push({key: e[0], value: e[1]})
|
||||
})
|
||||
return callback(JSON.stringify(mix))
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
decode(data, callback){
|
||||
if (!data) return false
|
||||
try {
|
||||
const scheme = JSON.parse(data)
|
||||
let mix = {};
|
||||
scheme.forEach((e)=>{
|
||||
mix[e.key] = e.value
|
||||
})
|
||||
return callback(mix)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
handleChanges(key, value){
|
||||
let { style } = this.state
|
||||
try {
|
||||
switch (key) {
|
||||
case "backgroundImage":{
|
||||
if(style.backgroundColor){
|
||||
this.handleRemove("backgroudColor")
|
||||
}
|
||||
style[key] = value
|
||||
this.encode(style, (res) => {
|
||||
app.app_theme.set(res)
|
||||
this.setPredominantColor(value)
|
||||
})
|
||||
return true
|
||||
}
|
||||
case "backgroundColor":{
|
||||
if(style.backgroundImage){
|
||||
this.handleRemove("backgroundImage")
|
||||
}
|
||||
style[key] = value
|
||||
this.encode(style, (res) => {
|
||||
app.app_theme.set(res)
|
||||
this.handleChanges("predominantColor", value)
|
||||
})
|
||||
}
|
||||
default:{
|
||||
style[key] = value
|
||||
this.encode(style, (res) => {
|
||||
app.app_theme.set(res)
|
||||
})
|
||||
}
|
||||
}
|
||||
this.decodeData()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
resetStyles(){
|
||||
app.app_theme.set([])
|
||||
}
|
||||
|
||||
handleRemove(key){
|
||||
try {
|
||||
@ -172,21 +297,6 @@ export default class ThemeSettings extends React.PureComponent{
|
||||
|
||||
}
|
||||
|
||||
setPredominantColor(furl){
|
||||
const _this = this
|
||||
const img = new Image();
|
||||
const url = ((furl.replace("url", "")).substring(1)).slice(0, -1);
|
||||
|
||||
img.crossOrigin = 'Anonymous';
|
||||
img.src = url
|
||||
|
||||
img.addEventListener('load', function() {
|
||||
const color = `rgb(${colorThief.getColor(img)})`
|
||||
_this.handleChanges("predominantColor", color)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
helper = {
|
||||
open: (e) => {
|
||||
this.setState({ helper_visible: true, helper_fragment: e })
|
||||
@ -195,25 +305,33 @@ export default class ThemeSettings extends React.PureComponent{
|
||||
this.setState({ helper_visible: false, helper_fragment: null })
|
||||
},
|
||||
backgroundImage: () => {
|
||||
this.helper.open(<BackgroundImage selectImg={(i) => this.handleChanges("backgroundImage", i)} />)
|
||||
this.helper.open(<BackgroundImage />)
|
||||
},
|
||||
backgroundColor: () => {
|
||||
this.helper.open(<BackgroundColor changeColor={(i) => this.handleChanges("backgroundColor", i)} />)
|
||||
this.helper.open(<BackgroundColor />)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
render(){
|
||||
const settingClick = { backgroundImage: () => this.helper.backgroundImage(), backgroundColor: () => this.helper.backgroundColor() }
|
||||
return(
|
||||
<div>
|
||||
<h2><Feather.Layers/> Theme</h2>
|
||||
<div>
|
||||
<button onClick={() => this.helper.backgroundImage()}> Background Image</button>
|
||||
<button onClick={() => this.helper.backgroundColor()}> Background Color </button>
|
||||
<button onClick={() => this.resetStyles()}> Reset Style </button>
|
||||
</div>
|
||||
<h2><Icons.Layers/> Theme</h2>
|
||||
<antd.List
|
||||
itemLayout="horizontal"
|
||||
dataSource={themeSettings}
|
||||
renderItem={item => (
|
||||
<antd.Card size="small" bodyStyle={{ width: '100%' }} style={{ display: "flex", flexDirection: "row", margin: 'auto' }} hoverable onClick={settingClick[item.id]}>
|
||||
<h3>{item.icon}{item.title} <div style={{ float: "right" }}><antd.Tag color={this.state.style[item.id]? "green" : "default"} > {this.state.style[item.id]? "Enabled" : "Disabled"} </antd.Tag></div></h3>
|
||||
<p>{item.description}</p>
|
||||
</antd.Card>
|
||||
)}
|
||||
/>
|
||||
|
||||
<antd.Drawer
|
||||
title="Theme Settings"
|
||||
placement="right"
|
||||
width="500"
|
||||
width="600px"
|
||||
closable={true}
|
||||
onClose={this.helper.close}
|
||||
visible={this.state.helper_visible}
|
||||
|
@ -0,0 +1,50 @@
|
||||
.background_image_controls{
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
> div {
|
||||
width: 100%;
|
||||
margin: 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.background_image_uploader{
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
text-align: center;
|
||||
|
||||
> div {
|
||||
width: 100%;
|
||||
margin: 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.background_image_preview{
|
||||
position: relative;
|
||||
height: 50%;
|
||||
|
||||
img{
|
||||
z-index: 9;
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.text_wrapper{
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
h1{
|
||||
font-size: 68px;
|
||||
}
|
||||
}
|
||||
}
|
@ -11,12 +11,16 @@
|
||||
@import './components/Menssaging.less';
|
||||
@import './components/PostCard.less';
|
||||
|
||||
@AppTheme_global_color: rgb(51, 51, 51);
|
||||
@AppTheme_global_color_accent: rgb(162, 162, 162);
|
||||
@AppTheme_global_background: rgb(248, 246, 248);
|
||||
|
||||
@__Global_backgroud_image: "";
|
||||
@AppTheme_global_color_dark: rgb(162, 162, 162);
|
||||
@AppTheme_global_background_dark: rgb(51, 51, 51);
|
||||
|
||||
@__Global_general_font_family: "Poppins", sans-serif;
|
||||
@__Global_texted_font: "Manrope", sans-serif;
|
||||
@__Global_alternative_font: "Netflix Sans";
|
||||
@__Global_alternative_font: "Netflix Sans", sans-serif;
|
||||
|
||||
@__Global_layout_backgroud: #F8F6F8;
|
||||
@__Global_layout_color: #2d2d2d;
|
||||
@ -24,22 +28,19 @@
|
||||
@__Global_layout_transitions-dur: 200ms;
|
||||
@__Global_Components_transitions_dur: 150ms;
|
||||
|
||||
|
||||
@__Global_SwapAnimDuration: 170ms;
|
||||
@__Global_backdrop_backgroud: rgba(158, 158, 158, 0.5);
|
||||
|
||||
@app_accent_gradient: linear-gradient(90deg, rgba(237,111,86,1) 0%, rgba(234,89,89,1) 100%);
|
||||
|
||||
@transition-ease-in: all 0.3s ease-out;
|
||||
@transition-ease-out: all 0.3s ease-out;
|
||||
@transition-ease-inout: all 150ms ease-in-out;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Overlay_wrapper_hidden_width: 22vw;
|
||||
@Overlay_wrapper_showFull_width: 94.2%;
|
||||
@Overlay_wrapper_showHalf_width: 35vw;
|
||||
@Overlay_container_bg_background: #F8F6F8;
|
||||
|
||||
|
||||
@Overlay_container_1_btn_backgroud: #4c4c4c;
|
||||
@ -72,12 +73,14 @@
|
||||
|
||||
#root {
|
||||
overflow: hidden;
|
||||
color: @AppTheme_global_color!important;
|
||||
background-color: @AppTheme_global_background!important;
|
||||
--accent_color: @AppTheme_global_color_accent;
|
||||
}
|
||||
|
||||
body {
|
||||
scroll-behavior: smooth;
|
||||
height: 100%;
|
||||
background-color: transparent;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
@ -86,7 +89,6 @@ body {
|
||||
|
||||
font-family: @__Global_texted_font;
|
||||
|
||||
background-color: @primary_layout_backgroud;
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
@left_sider_color: #333;
|
||||
@left_sider_color: @AppTheme_global_color;
|
||||
@left_sider_sizeIcons: 19px;
|
||||
@left_sider_menu__onhover_backgroud: rgb(80, 80, 80);
|
||||
@left_sider_menu__onhover_color: rgb(80, 80, 80);
|
Loading…
x
Reference in New Issue
Block a user