*update: contextual menu

*upadate: theme handlers & darkmodes

*added: window controllers api
This commit is contained in:
srgooglo 2020-09-19 01:32:54 +02:00
parent a863864644
commit c75f0744c2
17 changed files with 285 additions and 154 deletions

View File

@ -1,5 +1,6 @@
module.exports = { module.exports = {
app_config: { app_config: {
id: "comty",
siteName: 'Comty', siteName: 'Comty',
copyright: 'RageStudio©', copyright: 'RageStudio©',
MainPath: '/', MainPath: '/',
@ -12,6 +13,7 @@ module.exports = {
api_prefix: 'ycorejs_apiv3', api_prefix: 'ycorejs_apiv3',
app_settings_storage: 'app_settings', app_settings_storage: 'app_settings',
endpoint_global: 'https://comty.pw', endpoint_global: 'https://comty.pw',
proxy_local: 'http://localhost:8000',
session_token_storage: 'cid', session_token_storage: 'cid',
session_data_storage: 'data', session_data_storage: 'data',

14
globals/contextMenu.js Normal file
View File

@ -0,0 +1,14 @@
import * as Icons from 'components/Icons'
export default [
{
key: "inspect_element",
title: "Inspect",
icon: <Icons.Command />,
params: {
onClick: (e) => {
window.inspectElement(e)
}
}
}
]

View File

@ -20,8 +20,9 @@ const packagejson = require('../package.json')
const is = require('electron-is') const is = require('electron-is')
const waitOn = require('wait-on'); const waitOn = require('wait-on');
const { getDoNotDisturb } = require('electron-notification-state'); const { getDoNotDisturb } = require('electron-notification-state');
const { app_config } = require("../config");
let app_path = is.dev()? 'http://127.0.0.1:8000/' : `file://${path.join(__dirname, '..', 'renderer')}/index.html`; let app_path = is.dev()? app_config.proxy_local : `file://${path.join(__dirname, '..', 'renderer')}/index.html`;
let mainWindow; let mainWindow;
let tray; let tray;
let watcher; let watcher;
@ -272,6 +273,5 @@ ipcMain.handle('contextualMenu', (event, payload) => {
}) })
ipcMain.handle('inspectElement', (event, payload) => { ipcMain.handle('inspectElement', (event, payload) => {
log.log(payload)
mainWindow.inspectElement(payload.x, payload.y) mainWindow.inspectElement(payload.x, payload.y)
}) })

View File

@ -51,6 +51,7 @@
"electron-updater": "^4.3.4", "electron-updater": "^4.3.4",
"enquire-js": "^0.2.1", "enquire-js": "^0.2.1",
"feather-reactjs": "^2.0.13", "feather-reactjs": "^2.0.13",
"html2canvas": "^1.0.0-rc.7",
"jquery": "^3.5.1", "jquery": "^3.5.1",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"less-vars-to-js": "^1.3.0", "less-vars-to-js": "^1.3.0",

View File

@ -10,8 +10,10 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
font-size: 14px; font-size: 14px;
user-select: none;
> div{ > div{
transition: all 100ms linear;
cursor: pointer; cursor: pointer;
display: flex; display: flex;
@ -26,4 +28,8 @@
background-color: #e3e3e3; background-color: #e3e3e3;
color: rgba(36, 36, 36, 0.7); color: rgba(36, 36, 36, 0.7);
} }
> div:active{
transform: scale(0.98);
filter: brightness(110%);
}
} }

View File

@ -18,27 +18,26 @@ export default class ContextMenu extends React.Component<ContextMenu_props>{
this.setWrapperRef = this.setWrapperRef.bind(this) this.setWrapperRef = this.setWrapperRef.bind(this)
this.handleClickOutside = this.handleClickOutside.bind(this) this.handleClickOutside = this.handleClickOutside.bind(this)
this.eventListener = document.addEventListener('click', this.handleClickOutside, false) this.eventListener = () => {
document.addEventListener('click', this.handleClickOutside, false)
this.listening = true
}
} }
setWrapperRef(node){ setWrapperRef(node){
this.wrapperRef = node this.wrapperRef = node
} }
handleClickOutside(event) { handleClickOutside(event) {
if ( this.props.visible || this.wrapperRef && !this.wrapperRef.contains(event.target)) { if ( this.props.visible && this.wrapperRef && !this.wrapperRef.contains(event.target)) {
window.contextMenu.toogle()
this.listening = false this.listening = false
window.contextMenu.toogle()
document.removeEventListener('click', this.eventListener, false) document.removeEventListener('click', this.eventListener, false)
} }
} }
componentDidUpdate(){ componentDidUpdate(){
if (!this.listening) { !this.listening ? this.eventListener() : null
this.listening = true
this.eventListener
}
} }
render(){ render(){

View File

@ -9,10 +9,8 @@ import classnames from 'classnames'
import settings from 'core/libs/settings' import settings from 'core/libs/settings'
import { router } from 'core/cores' import { router } from 'core/cores'
import { notify } from 'core/libs/interface'
import LikeBtn from './components/like' import LikeBtn from './components/like'
import { connect } from 'umi' import { connect } from 'umi'
import config from 'config'
const { Meta } = antd.Card const { Meta } = antd.Card
@ -33,6 +31,44 @@ const defaultPayload = {
ReportIgnore: false, ReportIgnore: false,
} }
const contextMenuPost = [
{
key: "inspect_element",
title: "Copy URL",
icon: <Icons.Clipboard />,
params: {
onClick: (e) => {
core.writeToClipboard(core.generatePostURI(e.id))
}
}
},
{
key: "screenshot",
title: "Save screenshot",
icon: <Icons.Aperture />,
params: {
itemProps: {
style: { color: "#40a9ff" }
},
onClick: (e) => {
core.createScreenshotFromElement(document.getElementById(e.id))
}
}
},
{
key: "require_test",
title: "Require Test => DEV",
icon: <Icons.Cloud />,
params: {
onClick: (e) => {
console.log('Heeeey you developeeer')
},
keepOnClick: true,
require: "dev"
}
}
]
@connect(({ app }) => ({ app })) @connect(({ app }) => ({ app }))
export default class PostCard extends React.Component { export default class PostCard extends React.Component {
state = { state = {
@ -47,13 +83,6 @@ export default class PostCard extends React.Component {
}) })
} }
generatePostURI(id){
if(config.app_config.endpoint_global && id){
return `${config.app_config.endpoint_global}/post/${id}`
}
return null
}
goElementById(id){ goElementById(id){
document.getElementById(id).scrollIntoView({ document.getElementById(id).scrollIntoView({
behavior: "smooth", behavior: "smooth",
@ -66,19 +95,6 @@ export default class PostCard extends React.Component {
this.setState({ visibleMoreMenu: !this.state.visibleMoreMenu }) this.setState({ visibleMoreMenu: !this.state.visibleMoreMenu })
} }
handleActions(){
}
writeToClipboard(text){
navigator.clipboard.writeText(text)
.then(() => {
notify.info('Copy to clipboard')
}, () => {
/* failure */
})
}
renderReportedPost(){ renderReportedPost(){
if(this.state.ReportIgnore) return null if(this.state.ReportIgnore) return null
return ( return (
@ -160,6 +176,8 @@ export default class PostCard extends React.Component {
} }
render() { render() {
//
const actions = [ const actions = [
<LikeBtn count={this.state.payload.post_likes} liked={core.booleanFix(this.state.payload.is_liked)} />, <LikeBtn count={this.state.payload.post_likes} liked={core.booleanFix(this.state.payload.is_liked)} />,
<Icons.Share2 />, <Icons.Share2 />,
@ -169,12 +187,12 @@ export default class PostCard extends React.Component {
] ]
return ( return (
<div className={styles.post_card_wrapper}> <div key={this.state.payload.id} id={this.state.payload.id} className={styles.post_card_wrapper}>
<antd.Card <antd.Card
className={settings("post_hidebar") ? null : styles.showMode} className={settings("post_hidebar") ? null : styles.showMode}
onDoubleClick={() => null} onDoubleClick={() => null}
onClick={() => this.goElementById(this.state.payload.id)} onClick={() => this.goElementById(this.state.payload.id)}
onContextMenu={() => this.writeToClipboard(this.generatePostURI(this.state.payload.id))} onContextMenu={(e) => { window.contextMenu.open({ xPos: e.clientX, yPos: e.clientY, fragment: window.contextMenu.generate(contextMenuPost, this.state.payload) }) }}
actions={actions} actions={actions}
hoverable hoverable
> >

View File

@ -6,14 +6,14 @@ import { i18n, app_config } from 'config';
import * as errorHandlers from 'core/libs/errorhandler' import * as errorHandlers from 'core/libs/errorhandler'
import platform from 'platform' import platform from 'platform'
import request from 'request' import request from 'request'
import html2canvas from 'html2canvas'
const { pathToRegexp } = require('path-to-regexp'); const { pathToRegexp } = require('path-to-regexp');
export const languages = i18n ? i18n.languages.map(item => item.key) : []; export const languages = i18n ? i18n.languages.map(item => item.key) : [];
export const defaultLanguage = i18n ? i18n.defaultLanguage : ''; export const defaultLanguage = i18n ? i18n.defaultLanguage : '';
import './libs' import * as libs from './libs'
import './cores'
export const package_json = require('../../package.json'); export const package_json = require('../../package.json');
export const UUAID = `${package_json.name}==${package_json.UUID}`; export const UUAID = `${package_json.name}==${package_json.UUID}`;
@ -29,6 +29,35 @@ export const app_info = {
layout: platform.layout layout: platform.layout
}; };
export function createScreenshotFromElement(element){
if (!element) return false
html2canvas(element, {
useCORS: true,
proxy: app_config.proxy_local,
scale: 4,
backgroundColor: "transparent"
}).then(canvas => {
downloadEncodedURI({ data: canvas.toDataURL() })
})
}
export function generatePostURI(id){
if(app_config.endpoint_global && id){
return `${app_config.endpoint_global}/post/${id}`
}
return null
}
export function writeToClipboard(text){
navigator.clipboard.writeText(text)
.then(() => {
libs.Interface.notify.info('Copy to clipboard')
}, () => {
/* failure */
})
}
// [Experimental], not in use // [Experimental], not in use
export function getGlobals(params, callback) { export function getGlobals(params, callback) {
if (!params || !params.server) return false if (!params || !params.server) return false
@ -79,12 +108,32 @@ export function urlToBase64(url, callback){
xhr.send(); xhr.send();
} }
export function b64toBlob(b64Data, contentType='', sliceSize=512){
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
/** /**
* Generate a download with encoded uri * Generate a download with encoded uri
* *
* @param {object} payload - Generation Data * @param {object} payload - Generation Data
*/ */
export function downloadEncodedURI(payload){ export function downloadDecodedURI(payload){
if(!payload) return false if(!payload) return false
let { data, type, charset, filename } = payload let { data, type, charset, filename } = payload
/** /**
@ -94,7 +143,7 @@ export function downloadEncodedURI(payload){
if (!data || !type) return false if (!data || !type) return false
try { try {
if (!filename) { if (!filename) {
filename = `export_${time.now()}.${type.split("/")[1]}` filename = `${app_config.id}_${time.now()}.${type.split("/")[1]}`
} }
let tmp = document.createElement('a') let tmp = document.createElement('a')
tmp.href = `data:${type};charset=${charset},${encodeURIComponent(data)}` tmp.href = `data:${type};charset=${charset},${encodeURIComponent(data)}`
@ -105,6 +154,26 @@ export function downloadEncodedURI(payload){
} }
} }
export function downloadEncodedURI(payload){
if(!payload) return false
let { data, filename } = payload
/**
*
* @param {object} payload - Generation Data
*/
if (!data) return false
try {
if (!filename) {
filename = `${app_config.id}_${time.now()}.${data.split("/")[1].split(";")[0]}`
}
let tmp = document.createElement('a')
tmp.href = data
tmp.download= filename
tmp.click()
} catch (error) {
errorHandlers.onError.internal_proccess(error)
}
}
/** /**
* Return the last object from array * Return the last object from array
* *

View File

@ -1,7 +1,7 @@
import * as React from 'react' import * as React from 'react'
import * as antd from 'antd' import * as antd from 'antd'
import * as Icons from 'components/Icons' import * as Icons from 'components/Icons'
import { downloadEncodedURI } from 'core' import { downloadDecodedURI } from 'core'
export interface exportData_props { export interface exportData_props {
data: string; data: string;
@ -25,7 +25,7 @@ const exportData_render = (props: exportData_props) => {
antd.Modal.confirm({ antd.Modal.confirm({
title: <div><Icons.Code /> Your export <antd.Tag> {`${props.type.split("/")[1]}`} </antd.Tag></div>, title: <div><Icons.Code /> Your export <antd.Tag> {`${props.type.split("/")[1]}`} </antd.Tag></div>,
icon: null, icon: null,
onOk: () => downloadEncodedURI({data: props.data, type: props.type}), onOk: () => downloadDecodedURI({data: props.data, type: props.type}),
okText: <><Icons.Download />Download as File</> , okText: <><Icons.Download />Download as File</> ,
cancelText: "Done", cancelText: "Done",
content: exportCodeRender(props.data), content: exportCodeRender(props.data),

View File

@ -13,22 +13,12 @@ import classnames from 'classnames'
import { app_config } from 'config' import { app_config } from 'config'
import { theme } from 'core/libs/style' import { theme } from 'core/libs/style'
import * as antd from 'antd' import * as antd from 'antd'
import * as Icons from 'components/Icons' import contextMenuList from 'globals/contextMenu'
import styles from './PrimaryLayout.less' import styles from './PrimaryLayout.less'
const contextMenuList = [
{
key: "inspect_element",
title: "Inspect",
icon: <Icons.Command />
}
]
const { Content } = antd.Layout const { Content } = antd.Layout
const { Sider, Overlay, ContextMenu } = AppLayout const { Sider, Overlay, ContextMenu } = AppLayout
const isActive = (key) => { return key? key.active : false } const isActive = (key) => { return key? key.active : false }
const currentTheme = theme.get()
@withRouter @withRouter
@connect(({ app, loading }) => ({ app, loading })) @connect(({ app, loading }) => ({ app, loading }))
@ -39,54 +29,91 @@ class PrimaryLayout extends React.Component {
collapsed: app_config.default_collapse_sider ? true : false, collapsed: app_config.default_collapse_sider ? true : false,
isMobile: false isMobile: false
}, },
this.handleContextMenu = document.getElementById("root").addEventListener("contextmenu", (e) => {
this.handleContextMenu = window.addEventListener("contextmenu", (e) => {
e.preventDefault() e.preventDefault()
window.contextMenu.open({ xPos: e.clientX, yPos: e.clientY, fragment: this.generateContextMenu() }) window.contextMenu.open({ xPos: e.clientX, yPos: e.clientY, fragment: window.contextMenu.generate(contextMenuList, e) })
}, false) }, false)
window.DarkMode = isActive(currentTheme["darkmode"])? true : false
window.contextMenu = this.props.app.contextMenu // include API extensions
window.contextMenu.toogle = () => { window.requireQuery = (require) =>{
return new Promise(resolve => {
this.props.dispatch({ this.props.dispatch({
type: "app/updateState", type: 'app/isUser',
payload: {contextMenu: {...this.props.app.contextMenu, visible: !this.props.app.contextMenu.visible} } payload: require,
callback: (e) => {
resolve(e)
}
})
}) })
} }
window.contextMenu.open = (payload) => { window.inspectElement = (e) => this.props.dispatch({
if (!payload) return false
const fragment = payload.fragment || null
const xPos = payload.xPos || null
const yPos = payload.yPos || null
this.props.dispatch({
type: "app/updateState",
payload: {contextMenu: {...this.props.app.contextMenu, xPos, yPos, fragment, visible: true}}
})
}
}
handleContextMenuActions = {
inspect_element: (e) =>{
this.props.dispatch({
type: "app/ipcInvoke", type: "app/ipcInvoke",
payload: { payload: {
key: "inspectElement", key: "inspectElement",
payload: { x: e.clientX, y: e.clientY } payload: { x: e.clientX, y: e.clientY }
} }
}) })
}
window.contextMenu = this.props.app.contextMenu
window.contextMenu.open = (payload) => {
if (!payload) return false
this.props.dispatch({
type: "app/updateState",
payload: {contextMenu: {
...this.props.app.contextMenu,
xPos: payload.xPos,
yPos: payload.yPos,
fragment: payload.fragment,
visible: true
}}
})
} }
generateContextMenu() { window.contextMenu.handle = (e, ...rest) => {
return contextMenuList.map((e) => { if(!e || typeof(e) == 'undefined') {
return false
}
typeof(e.onClick) !== 'undefined' && e.onClick ? e.onClick(...rest) : null
typeof(e.keepOnClick) !== 'undefined' && e.keepOnClick ? null : window.contextMenu.toogle()
}
window.contextMenu.generate = (payload, ...rest) => {
if(!payload) return false
let tmp = []
payload.forEach(async(e) => {
if (typeof(e.params.require) !== 'undefined') {
if(await window.requireQuery(e.params.require)){
e.valid = true
tmp.push(e)
}else{
// bruh
}
}else{
tmp.push(e)
}
})
return tmp.map((e) => {
return( return(
<div onClick={this.handleContextMenuActions[e.key]} key={e.key}> <div {...e.params.itemProps} onClick={() => window.contextMenu.handle(e.params, ...rest)} key={e.key}>
{e.icon}{e.title} {e.icon}{e.title}
</div> </div>
) )
}) })
} }
window.contextMenu.toogle = () => {
this.props.dispatch({
type: "app/updateState",
payload: {contextMenu: {...this.props.app.contextMenu, visible: !this.props.app.contextMenu.visible} }
})
}
}
componentDidMount() { componentDidMount() {
this.handleContextMenu this.handleContextMenu
@ -116,31 +143,13 @@ class PrimaryLayout extends React.Component {
const { collapsed, isMobile } = this.state const { collapsed, isMobile } = this.state
const { onCollapseChange } = this const { onCollapseChange } = this
const { contextMenu } = app const { contextMenu } = app
const app_theme = isActive(currentTheme["darkmode"])? "dark" : null const currentTheme = theme.get()
const breakpoint = { const SiderProps = { isMobile, collapsed, onCollapseChange }
xs: '480px', const OverlayProps = { isMobile }
sm: '576px',
md: '768px',
lg: '992px',
xl: '1200px',
xxl: '1600px',
}
const SiderProps = {
breakpoint,
isMobile,
collapsed,
onCollapseChange,
app_theme
}
const OverlayProps = {
breakpoint,
isMobile,
app_theme
}
window.darkMode = isActive(currentTheme["darkmode"])? true : false
document.getElementsByTagName("body")[0].setAttribute("class", window.darkMode? "dark" : "light")
return ( return (
<React.Fragment> <React.Fragment>
@ -164,7 +173,10 @@ class PrimaryLayout extends React.Component {
overflow: "hidden", overflow: "hidden",
opacity: currentTheme.backgroundImage.opacity opacity: currentTheme.backgroundImage.opacity
}} /> : null} }} /> : null}
<antd.Layout id="app" className={classnames(styles.app, {[styles.interfaced]: this.props.app.electron, [styles.dark_mode]: isActive(currentTheme['darkmode']) } )}> <antd.Layout id="app" className={classnames(styles.app, {
[styles.interfaced]: this.props.app.electron,
[styles.dark_mode]: window.darkMode
} )}>
<Sider {...SiderProps} /> <Sider {...SiderProps} />
<div className={styles.primary_layout_container}> <div className={styles.primary_layout_container}>
<Content <Content

View File

@ -1,9 +1,14 @@
import React, { Component } from 'react' import React from 'react'
import BaseLayout from './BaseLayout' import BaseLayout from './BaseLayout'
import { withRouter } from 'umi' import { withRouter } from 'umi'
const appBody = document.getElementsByTagName("body")[0]
@withRouter @withRouter
class Layout extends Component { class Layout extends React.Component {
componentDidMount(){
const appBody = document.getElementsByTagName("body")[0]
appBody.setAttribute("id", "appWrapper")
}
render() { render() {
const { children } = this.props const { children } = this.props
return ( return (

View File

@ -87,12 +87,12 @@ export default {
}, },
effects: { effects: {
*query({ payload }, { call, put, select }) { *query({ payload }, { call, put, select }) {
const service = yield select(state => state.app.service_valid); const service = yield select(state => state.app.service_valid)
const session = yield select(state => state.app.session_valid); const session = yield select(state => state.app.session_valid)
const sessionDataframe = yield select(state => state.app.session_data) const sessionDataframe = yield select(state => state.app.session_data)
if (!service) { if (!service) {
console.error('❌ Cannot connect with validate session service!'); console.error('❌ Cannot connect with validate session service!')
} }
if (!sessionDataframe && session ) { if (!sessionDataframe && session ) {
@ -251,9 +251,7 @@ export default {
isDev: sessionData.dev, isDev: sessionData.dev,
isPro: sessionData.is_pro isPro: sessionData.is_pro
}, },
exp: settings("session_noexpire") exp: Math.floor(Date.now() / 1000) * 120
? 0
: Math.floor(Date.now() / 1000) + 60 * 60,
} }
jwt.sign(frame, state.server_key, (err, token) => { jwt.sign(frame, state.server_key, (err, token) => {
@ -285,7 +283,7 @@ export default {
try { try {
const session_data = JSON.stringify(JSON.parse(res)["user_data"]) const session_data = JSON.stringify(JSON.parse(res)["user_data"])
sessionStorage.setItem(app_config.session_data_storage, btoa(session_data)) sessionStorage.setItem(app_config.session_data_storage, btoa(session_data))
state.session_data = session_data location.reload()
} catch (error) { } catch (error) {
verbosity.error(error) verbosity.error(error)
} }
@ -364,6 +362,8 @@ export default {
state.session_authframe = null; state.session_authframe = null;
cookie.remove(app_config.session_token_storage) cookie.remove(app_config.session_token_storage)
sessionStorage.clear() sessionStorage.clear()
router.push('/')
location.reload()
}, },
}, },
}; };

View File

@ -6,6 +6,7 @@ import { connect } from 'umi'
import settings from 'core/libs/settings' import settings from 'core/libs/settings'
import { PostCard, PostCreator } from 'components' import { PostCard, PostCreator } from 'components'
import * as antd from 'antd' import * as antd from 'antd'
import styles from './index.less'
@connect(({ app }) => ({ app })) @connect(({ app }) => ({ app }))
export default class Explore extends React.Component { export default class Explore extends React.Component {
@ -55,14 +56,12 @@ export default class Explore extends React.Component {
} }
return( return(
<div> <div className={styles.exploreWrapper}>
<List <List
//loadMore={loadMore} //loadMore={loadMore}
dataSource={this.state.feed} dataSource={this.state.feed}
renderItem={item => ( renderItem={item => (
<div id={item.id}> <PostCard payload={item}/>
<PostCard payload={item} key={item.id} />
</div>
)} )}
/> />
</div> </div>

View File

@ -0,0 +1,3 @@
.exploreWrapper{
}

View File

@ -8,6 +8,9 @@ import * as Icons from 'components/Icons'
export default class Logout extends React.Component{ export default class Logout extends React.Component{
componentDidMount(){ componentDidMount(){
if (!this.props.app.session_valid) {
return false
}
const dispatchLogout = () => this.props.dispatch({ type: "app/logout" }) const dispatchLogout = () => this.props.dispatch({ type: "app/logout" })
antd.Modal.confirm({ antd.Modal.confirm({

View File

@ -128,8 +128,8 @@ class BackgroundImage extends ThemeConfigurator{
key: "backgroundImage", key: "backgroundImage",
model: { active: false, opacity: null, src: null }, model: { active: false, opacity: null, src: null },
textColor: this.rgbToScheme(getComputedStyle(document.getElementById("root")).color), textColor: this.rgbToScheme(getComputedStyle(document.getElementById("appWrapper")).color),
overlayColor: this.rgbToScheme(getComputedStyle(document.getElementById("root")).backgroundColor), overlayColor: this.rgbToScheme(getComputedStyle(document.getElementById("appWrapper")).backgroundColor),
processing: null, processing: null,
customURL: '', customURL: '',

View File

@ -36,26 +36,20 @@
background-color: transparent; background-color: transparent;
} }
#root{
background-color: @AppTheme_global_background!important;
color: @AppTheme_global_color!important;
}
.app{ .app{
&.interfaced{ &.interfaced{
height: calc(100% - @AppTheme_global_winavbar_height)!important; height: calc(100% - @AppTheme_global_winavbar_height)!important;
} }
&.dark_mode{ &.dark_mode{
filter: invert(100%);
:global{ :global{
.ant-card{ filter: invert(100%);
background: @AppTheme_global_background_dark!important; img, svg, video {
filter: invert(100%);
color: @AppTheme_global_background;
} }
} }
} }
} }
#app { #app {
@ -64,7 +58,6 @@
position: absolute; position: absolute;
bottom: 0; bottom: 0;
color: @AppTheme_global_color!important;
background-repeat: repeat-x; background-repeat: repeat-x;
background-size: cover; background-size: cover;
background-position-y: center; background-position-y: center;
@ -89,6 +82,8 @@
} }
body { body {
-webkit-app-region: no-drag; -webkit-app-region: no-drag;
@ -101,7 +96,12 @@ body {
line-height: @base-line-height; line-height: @base-line-height;
font-family: @__Global_texted_font; font-family: @__Global_texted_font;
background-color: @AppTheme_global_background!important; color: @AppTheme_global_color!important;
background-color: @AppTheme_global_background;
&.dark{
background-color: @AppTheme_global_color;
}
} }
@media (max-width: @bp-small){ @media (max-width: @bp-small){