update: customization, optimization, core

This commit is contained in:
srgooglo 2020-05-13 13:17:03 +02:00
parent 7b48c13c43
commit 6923ce90c9
81 changed files with 1600 additions and 475 deletions

View File

@ -3,7 +3,10 @@ import { resolve } from 'path'
import { i18n } from './config/ycore.config.js'
export default {
ignoreMomentLocale: true,
hash: true,
hash: false,
ssr: false,
targets: { ie: 9,},
treeShaking: true,
plugins: [
@ -65,6 +68,7 @@ export default {
// Webpack Configuration
alias: {
app: resolve(__dirname, './src/@app/app.js'),
keys: resolve(__dirname, './config/keys.js'),
globals: resolve(__dirname, './globals'),
components: resolve(__dirname, './src/components'),
config: resolve(__dirname, './config/ycore.config.js'),

View File

@ -1,6 +1,8 @@
module.exports = {
// Global Server Key (Requiered for RS-YIBTP), Not autogenerated, must be included on. (Recommended not modify this constants)
server_key:
'f706b0a535b6c2d36545c4137a0a3a26853ea8b5-1223c9ba7923152cae28e5a2e7501b2b-50600768',
unsplash_key: "slrHmuo9FEJajV4xvWl38TUhbib6BhhGI4VIZ1-cqnw",
unsplash_secret: "dh3UlgLTdunO7a_l_iKjotXbz0xB7w5EuDIBU8Pa8pA",
g_recaptcha_key: '6Lc55uUUAAAAAEIACMVf3BUzAJSNCmI3RrjEirZ6',
g_recaptcha_secret: '6Lc55uUUAAAAAOP4OgUa5DpqJC-70t53AmW0lyYf',
// Global Server Key (Requiered for RS-YIBTP), Not autogenerated, must be included on. (Recommended not modify this constant)
server_key: 'f706b0a535b6c2d36545c4137a0a3a26853ea8b5-1223c9ba7923152cae28e5a2e7501b2b-50600768',
}

View File

@ -3,6 +3,5 @@ const path = require('path')
const lessToJs = require('less-vars-to-js')
module.exports = () => {
const themePath = path.join(__dirname, `../src/themes/index.less`)
return lessToJs(fs.readFileSync(themePath, 'utf8'))
// return {"@__Global_backgroud_image": "url(https://images.unsplash.com/photo-1471286274405-579f8d7132d8?.jpg)"}
}

View File

@ -8,19 +8,21 @@ module.exports = {
DarkLogoPath: '/dark_logo.svg',
resource_bundle: 'light_ng',
sync_server: 'http://localhost:5500',
server_endpoint: 'https://comty.pw',
g_recaptcha_key: '6Lc55uUUAAAAAEIACMVf3BUzAJSNCmI3RrjEirZ6',
g_recaptcha_secret: '6Lc55uUUAAAAAOP4OgUa5DpqJC-70t53AmW0lyYf',
sync_server: 'http://85.251.59.39:6050',
rest_server: 'https://comty.pw',
/* Layout configuration, specify which layout to use for route. */
layouts: [
{
name: 'primary',
include: [/.*/],
exclude: [/\/login/, /\/socket\/(.*)/, /\/publics/, /\/authorize/],
include: [/\/main/, /\/settings/, /\/saves/, /\/pro/, /\/chats/, /\//],
exclude: [/\/publics/, /\/login/ ],
},
{
name: 'public',
include: [/.*/]
}
],
i18n: {

View File

@ -1,13 +1,12 @@
import * as Icons from '@ant-design/icons'
export var BadgesType = [
{
id: 'alpha_test',
title: 'Alpha Tester',
color: 'green',
require: '',
icon: (<Icons.BugOutlined />),
icon: (<Icons.BugOutlined />),
tip: 'Oh yeah!'
},
{
@ -41,5 +40,13 @@ export var BadgesType = [
require: '',
icon: (<Icons.SmileOutlined />),
tip: 'hump....',
},
{
id: 'el_walter_pro',
title: 'Pro Chikito',
color: '#a0d911',
require: '',
icon: (<Icons.AndroidOutlined />),
tip: 'Chikito',
}
]

View File

@ -1,2 +1,3 @@
export * from './comty_endpoints.js'
export * from './twitter_endpoints.js'
export * from './unsplash_endpoints.js'

View File

@ -0,0 +1,5 @@
module.exports = {
autorize: 'https://accounts.spotify.com/authorize',
}

View File

@ -0,0 +1,6 @@
module.exports = {
unsplash_endpoints: {
api: "https://api.unsplash.com/",
search: "https://api.unsplash.com/search/photos"
}
}

6
globals/links.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
gitlab: "https://gitlab.com/rstudio-development/comty-development",
github:"https://github.com/srgooglo/Comty-Development",
trellojoin: "https://trello.com/invite/b/UbwvlG1I/2bc02725b9b210d2e9e9a82c5040b895/comty-development",
patreon: "https://www.patreon.com/rstudio",
}

44
globals/sidebar_menu.js Normal file
View File

@ -0,0 +1,44 @@
import * as Icons from '@ant-design/icons'
import Icon from '@ant-design/icons'
import {CustomIcons} from 'components'
import * as Feather from 'feather-reactjs'
let MenuList = [
{
id: 'main',
title: 'Main',
path: '/main',
require: 'login',
icon: <Feather.Home />,
},
{
id: 'explore',
title: 'Explore',
path: '/explore',
require: 'login',
icon: <Feather.Compass />,
},
{
id: 'saves',
title: 'Saves',
path: '/saves',
require: 'login',
icon: <Feather.Bookmark />,
},
{
id: 'messages',
title: 'Messages',
path: '/messages',
require: 'login',
icon: <Feather.MessageSquare />,
},
{
id: 'notifications',
title: 'Notifications',
path: '/notifications',
require: 'login',
icon: <Feather.Inbox/>,
},
]
export default MenuList

View File

@ -2,8 +2,7 @@
"name": "Comty",
"start_url": ".",
"display": "standalone",
"background_color": "white",
"description": "RageStudio users dashboard",
"description": "An client prototype of universal social network.",
"icons": [
{
"src": "logo.svg"

View File

@ -3,7 +3,7 @@
"UUID": "C8mVSr-4nmPp2-pr5Vrz-CU4kg4",
"title": "Comty™",
"DevBuild": true,
"version": "0.4.06",
"version": "0.4.11",
"stage": "dev-pre",
"description": "",
"author": "RageStudio",
@ -15,27 +15,35 @@
"@material-ui/core": "^4.9.9",
"@material-ui/icons": "^4.9.1",
"antd": "^4.1.2",
"axios": "^0.19.2",
"canvas": "^2.6.1",
"classnames": "^2.2.6",
"colorthief": "^2.3.0",
"dva": "2.4.1",
"dva-model-extend": "^0.1.2",
"enquire-js": "^0.2.1",
"express": "^4.17.1",
"feather-reactjs": "^2.0.9",
"feather-reactjs": "^2.0.13",
"interactjs": "^1.9.9",
"jquery": "^3.4.1",
"jsonwebtoken": "^8.5.1",
"koa": "^2.7.0",
"koa-compress": "^3.0.0",
"koa-mount": "^4.0.0",
"koa-static": "^5.0.0",
"localforage": "^1.7.3",
"lodash": "^4.17.15",
"md5": "^2.2.1",
"moment": "^2.24.0",
"node-sass": "^4.13.1",
"nodemon": "^1.19.1",
"nprogress": "^0.2.0",
"path-to-regexp": "^6.1.0",
"peerjs": "^1.2.0",
"prop-types": "^15.7.2",
"puppeteer": "^3.0.3",
"radium": "^0.26.0",
"randomstring": "^1.1.5",
"react-animations": "^1.0.0",
"react-color": "^2.18.1",
"react-dazzle": "^1.4.0",
"react-emoji": "^0.5.0",
"react-feather": "^2.0.8",
@ -53,6 +61,8 @@
"ts-cookies": "^1.0.0",
"umi": "^2.13.12",
"umi-plugin-react": "^1.15.7",
"umi-request": "^1.2.4",
"umi-server": "^1.2.3",
"validator": "^12.2.0",
"ycorejs": "^0.1.1"
},

51
server.js Normal file
View File

@ -0,0 +1,51 @@
require('regenerator-runtime/runtime');
const server = require('umi-server');
const Koa = require('koa');
const compress = require('koa-compress');
const mount = require('koa-mount');
const { join, extname } = require('path');
const isDev = process.env.NODE_ENV === 'development';
const root = join(__dirname, 'dist');
const render = server({
root,
polyfill: false,
dev: isDev,
stream: true,
});
const app = new Koa();
app.use(
compress({
threshold: 2048,
flush: require('zlib').Z_SYNC_FLUSH,
}),
);
app.use(async (ctx, next) => {
const ext = extname(ctx.request.path);
// 符合要求的路由才进行服务端渲染,否则走静态文件逻辑
if (!ext) {
ctx.type = 'text/html';
ctx.status = 200;
const { ssrStream } = await render({
req: {
url: ctx.request.url,
},
});
ctx.body = ssrStream;
} else {
await next();
}
});
app.use(mount('/dist', require('koa-static')(root)));
if (!process.env.NOW_ZEIT_ENV) {
app.listen(3000);
console.log('http://localhost:3000');
}
module.exports = app.callback();

View File

@ -1,16 +1,10 @@
/**
* @yCore_Worker
*
* @author rStudio© 2020
* @license Pending...
*/
import * as Endpoints from 'globals/endpoints/index.js'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import localforage from 'localforage'
import { format } from 'timeago.js'
import * as antd from 'antd'
import moment from 'moment'
import React from 'react'
import config from 'config'
import './libs.js'
@ -19,11 +13,11 @@ export * from '../../config/app.settings.js'
export * from './libs.js'
export * from 'utils'
export var endpoints = Endpoints
export const package_json = require('../../package.json')
export const UUAID = `${package_json.name}==${package_json.UUID}`
export const endpoints = Endpoints
const prefix = package_json.name
export const AppInfo = {
apid: package_json.name,
@ -175,6 +169,18 @@ export function arrayRemoveByID(arr, value) {
return ele.id != value
})
}
/**
* Remove an element by key from an array
*
* @param array {array}
* @param value {string}
* @return object
*/
export function arrayRemoveByKEY(arr, value) {
return arr.filter(function(ele) {
return ele.key != value
})
}
/**
* Global fix for convert '1, 0' to string boolean 'true, false'
@ -208,83 +214,6 @@ export const time = {
}
/**
* Framework functionality for show with interface an notification
*
*/
const {FieldTimeOutlined} = require('@ant-design/icons')
export const notify = {
expire: (...res) => {
antd.notification.error({
message: 'Hey ',
icon: <FieldTimeOutlined />,
description: res,
placement: 'bottomLeft',
})
},
info: (...res) => {
antd.notification.info({
message: 'Well',
description: res.toString(),
placement: 'bottomLeft',
})
},
exception: (...res) => {
antd.notification.error({
message: 'WoW!',
description: res.toString(),
placement: 'bottomLeft',
})
},
warn: (...res) => {
antd.notification.warn({
message: 'Hey!',
description: res.toString(),
placement: 'bottomLeft',
})
},
success: (...res) => {
antd.notification.success({
message: 'Well',
description: res.toString(),
placement: 'bottomLeft',
})
},
error: (...res) => {
antd.notification.error({
message: 'Wopss',
description: (
<div>
<span>An wild error appear! : </span>
<br />
<br />
<div
style={{
position: 'relative',
width: '100%',
backgroundColor: 'rgba(243, 19, 19, 0.329)',
bottom: '0',
color: 'black',
padding: '3px',
}}
>
{res.toString()}
</div>
</div>
),
placement: 'bottomLeft',
})
},
proccess: (...res) => {
antd.notification.open({
icon: <Icons.LoadingOutlined style={{ color: '#108ee9' }} />,
message: 'Please wait',
description: <div>{res}</div>,
placement: 'bottomLeft',
})
},
}
/**
* User console with setting user permissions
*
@ -309,6 +238,35 @@ export const yconsole = {
},
}
export const __yconsole = {
showLogs: SettingStoragedValue('force_showDevLogs')? true : false,
log: (...cont) => {
console.log(...cont)
logger.consoles.indexeddb.log(...cont);
},
debug: (...cont) => {
return logger.init(function() {
logger.on(function() {
console.debug(...cont);
});
}, null, {showLogs: yconsole.showLogs});
},
error: (...cont) => {
return logger.init(function() {
logger.on(function() {
console.error(...cont);
});
}, null, {showLogs: yconsole.showLogs});
},
warn: (...cont) => {
return logger.init(function() {
logger.on(function() {
console.warn(...cont);
});
}, null, {showLogs: yconsole.showLogs});
},
}
/**
* Request FullScreen mode
*
@ -328,3 +286,432 @@ export function requestFullscreen() {
elem.msRequestFullscreen()
}
}
export let logger = {
/**
* Is set with true or false after logger.init() invocation.
*/
isIndexedDBSupported: null,
showLogs: true,
//// private variables
databaseName: `${prefix}_ycoreLogger`,
database: null,
/**
* Initializes window.indexedDB and logger.isIndexedDBSupported.
* @param callbackSuccess invokes if browser supports IndexedDB.
* @param callbackFail (optional) invokes if browser does not supports IndexedDB.
*/
init: function(callbackSuccess, callbackFail, options) {
let indexedDB = window.indexedDB
let IDBTransaction = window.IDBTransaction
let IDBKeyRange = window.IDBKeyRange
// Check for options props
if (options) {
options.showLogs? logger.showLogs = options.showLogs : false
}
if (!indexedDB) {
if(callbackFail) {callbackFail();}
}
else {
if(!callbackSuccess) {
throw "IllegalAgrumentException. Please provide a callback for success initialization";
}
callbackSuccess();
}
},
/**
* Turns on catching all console.* methods invocations and saving logs into IndexedDB
* @param callback (optional) is invoked then database is successfully opened and console is replaced with logger.log2both.
*/
on: function(callback) {
if( logger.consoles.originalIsOn === false ) {
logger.consoles.originalIsOn = true;
if( logger.database != null ) {
logger.replaceConsoleThenOn(callback);
}
else {
logger.openDb(logger.databaseName, function() {
logger.replaceConsoleThenOn(callback);
});
}
}
},
off: function() {
if( logger.consoles.originalIsOn === true ) {
console = logger.consoles.original;
logger.consoles.originalIsOn = false;
}
},
isOn: function() {
return logger.consoles.originalIsOn;
},
clear: function() {
if(logger.database == null) {
throw "IllegalStateException: need to logger.init() and logger.on before clearing the database, e.g. logger.init(function(){logger.on(function(){logger.clear();});});";
}
logger.consoles.original.log("logger.clear");
var objectStore = logger.database.transaction("logs").objectStore("logs");
objectStore.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
// cursor.key + "=" + cursor.value
var request = logger.database.transaction(["logs"], "readwrite").objectStore("logs").delete(cursor.key);
request.onsuccess = function(event) {
// It's gone!
};
cursor.continue();
}
else {
logger.consoles.original.log("logs2indexeddb successfully cleared");
}
};
},
/**
* Opens a file with logs.
* If parameters are null (not specified) then method downloads all logs from database.
* If parameters are specified, then the method filters logs and provide only records
* that were created since fromDate to toDate.
* @param fromDate (optional)
* @param toDate (optional)
*/
download: function(fromDate, toDate) {
var fromTime = null;
var toTime = null;
if(fromDate != null) {
if(toDate != null) {
if(typeof(fromDate.getTime) === "undefined" || typeof(toDate.getTime) === "undefined" ) {
throw "IllegalArgumentException: parameters must be Date objects";
}
fromTime = fromDate.getTime();
toTime = toDate.getTime();
}
else {
throw "IllegalArgumentException: Please provide either both parameters or none of them";
}
}
var objectStore = logger.database.transaction("logs").objectStore("logs");
var data = '';
objectStore.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
var v = cursor.value;
if( fromTime == null || fromTime <= v.time && v.time <= toTime) {
data += new Date(v.time*1)+" "+ v.label+" "+ v.log+"\n";
}
cursor.continue();
}
else {
logger.downloadFile(data);
}
};
},
downloadToday: function() {
var start = new Date();
start.setHours(0,0,0,0);
var end = new Date();
end.setHours(23,59,59,999);
logger.download(start, end);
},
/**
* @private
*/
downloadFile: function(data){
if(!data) {
logger.consoles.original.log("logger.download: Empty database");
return;
}
var filename = 'console.log'
var blob = new Blob([data], {type: 'text/plain'}),
e = document.createEvent('MouseEvents'),
a = document.createElement('a')
a.download = filename
a.href = window.URL.createObjectURL(blob)
a.dataset.downloadurl = ['text/plain', a.download, a.href].join(':')
e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
a.dispatchEvent(e)
},
clearAndDrop: function() {
logger.clear();
// todo replace with database drop
},
consoles: {
originalIsOn: false,
/**
* @private Logs into both - console and indexeddb
*/
both: {
log: function(str) {
logger.showLogs ? logger.consoles.original.log(str) : null
logger.consoles.indexeddb.log(str);
},
warn: function(str) {
logger.showLogs ? logger.consoles.original.warn(str) : null
logger.consoles.indexeddb.warn(str);
},
trace: function(str) {
logger.showLogs ? logger.consoles.original.trace(str) : null
logger.consoles.indexeddb.trace(str);
},
error: function(str) {
logger.showLogs ? logger.consoles.original.error(str) : null
logger.consoles.indexeddb.error(str);
},
info: function(str) {
logger.showLogs ? logger.consoles.original.info(str) : null
logger.consoles.indexeddb.info(str);
},
debug: function(str) {
logger.showLogs ? logger.consoles.original.debug(str) : null
logger.consoles.indexeddb.debug(str);
}
},
/**
* @private Original console logger. No matter if logger is on or off. Is used for internal logger logging during test.
*/
original: console,
/**
* @public Logger that saves data into opened IndexedDB.
*/
indexeddb: {
log: function(str) {
logger.consoles.indexeddb.write2db('log', str);
},
warn: function(str) {
logger.consoles.indexeddb.write2db('warn', str);
},
trace: function(str) {
logger.consoles.indexeddb.write2db('trace', str);
},
error: function(str) {
logger.consoles.indexeddb.write2db('error', str);
},
info: function(str) {
logger.consoles.indexeddb.write2db('info', str);
},
debug: function(str) {
logger.consoles.indexeddb.write2db('debug', str);
},
write2db: function(label, str) {
var time = new Date();
time.setMonth(time.getMonth()-1);
var data = {
time: time.getTime()+'',
label: label,
log: str
};
logger.database.transaction(["logs"], "readwrite").objectStore("logs").add(data);
}
}
},
exceptions: {
uncatchable: {
on: function() {
if( logger.isOn() ) {
window.onerror = logger.exceptions.uncatchable.onerror.both;
}
else {
logger.consoles.original.warn("logger needs to be on to start catch uncatchable exceptions");
}
},
off: function() {
window.onerror = logger.exceptions.uncatchable.onerror.original;
},
onerror: {
original: window.onerror,
/**
* Logs exception into the database
*/
custom: function (errorMsg, url, lineNumber) {
logger.consoles.indexeddb.error(errorMsg+" "+url+" line:"+lineNumber);
return false;
},
both: function (errorMsg, url, lineNumber) {
logger.exceptions.uncatchable.onerror.custom("UNCATCHABLE: ----------------"+errorMsg, url, lineNumber);
if( logger.exceptions.uncatchable.onerror.original ) {
logger.exceptions.uncatchable.onerror.original(errorMsg, url, lineNumber);
}
}
}
}
},
/**
* @private Opens database and updates schema if needed.
* @param dbName database name
* @param callbackSuccessOpen (optional) invoked after success connect and update.
* @param onupgradeneeded (optional) function to create different structure of the database.
*/
openDb: function(dbName, callbackSuccessOpen, onupgradeneeded) {
logger.consoles.original.log("openDb ...");
// Let us open our database
var request = indexedDB.open(dbName, 2);
request.onerror = function (event) {
alert("Why didn't you allow my web app to use IndexedDB?!");
logger.consoles.original.error("openDb:", event.target.errorCode);
};
request.onsuccess = function (e) {
logger.database = request.result;
logger.consoles.original.log("openDb DONE");
logger.database.onerror = function (event) {
// Generic error handler for all errors targeted at this database's
// requests!
logger.consoles.original.error("Database error: " + event.target.errorCode);
};
if(callbackSuccessOpen) {callbackSuccessOpen();}
};
// This event is only implemented in recent browsers
request.onupgradeneeded = function (event) {
logger.consoles.original.log("openDb.onupgradeneeded");
var db = event.target.result;
var objectStore = db.createObjectStore("logs", { autoIncrement : true });
// Create an index to search by time
objectStore.createIndex("time", "time", { unique: false });
objectStore.createIndex("label", "label", { unique: false });
objectStore.transaction.oncomplete = function (event) {
logger.consoles.original.log("openDb.onupgradeneeded.transaction.oncomplete");
}
};
},
/**
* @private
*/
replaceConsoleThenOn: function(callback) {
console = logger.consoles.both;
logger.exceptions.uncatchable.on();
if( callback ) callback();
},
/**
* Performance test methods.
* Use
* $(function () { // This is JQuery construction that needed to be sure that html document is loaded
logger.init(function() {// successfully initialized
logger.debug.startIndexedDBTest(5000, 'status');
}, function() {// error
window.alert("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.");
logger.debug.status.html("<span style='color: red;>Error: Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.</span>");
});
});
* <p id="status"></p>
* to test 5000 writes.
*/
debug: {
statusElementId: null,
startTime: null,
totalNumberOfWrites: null,
/**
* Opens database and starts WriteTest
* @param n number of records to write during the test.
* @param statusElementId html element's id to write results of the test.
*/
startIndexedDBTest: function(n, statusElementId) {
if( !n || !statusElementId ) {
throw "IllegalArgumentsException";
}
logger.debug.statusElementId = statusElementId;
logger.debug.status('Testing...');
logger.openDb("logs2indexeddb_test", function() {
logger.debug.processWriteTest(logger.database, n);
}, logger.debug.onupgradeneeded);
},
onupgradeneeded: function (event) {
logger.consoles.original.log("debug.onupgradeneeded");
var db = event.target.result;
// Create an objectStore to hold information about our customers. We're
// going to use "ssn" as our key path because it's guaranteed to be
// unique.
var objectStore = db.createObjectStore("customers", { keyPath: "ssn" });
// Create an index to search customers by name. We may have duplicates
// so we can't use a unique index.
objectStore.createIndex("name", "name", { unique: false });
// Create an index to search customers by email. We want to ensure that
// no two customers have the same email, so use a unique index.
objectStore.createIndex("email", "email", { unique: true });
// Use transaction oncomplete to make sure the objectStore creation is
// finished
objectStore.transaction.oncomplete = function (event) {
logger.consoles.original.log("debug.onupgradeneeded.transaction.oncomplete");
}
},
/**
* @private
*/
processWriteTest: function(db, n) {
logger.consoles.original.log("processWriteTest");
logger.debug.status('Connected to database. Preparing to process ' + n + " writes.");
alert("The test can take a lot of time (1-2 minutes). The browser can be locked duting the test. Ready to launch?");
logger.debug.status("Testing... Please wait until test will be finished.");
logger.debug.totalNumberOfWrites = n;
logger.debug.startTime = new Date();
for (var i = 0; i < n; i++) {
// status("Writing "+i+" record..."); // Comment this to get real time estimate
logger.debug.processWrite(db, i);
}
// The write will be finished after last callback
},
/**
* @private
*/
testFinished: function () {
logger.consoles.original.log("testFinished");
var n = logger.debug.totalNumberOfWrites;
var end = new Date();
var diff = end.getMinutes() * 60 + end.getSeconds() - (logger.debug.startTime.getMinutes() * 60 + logger.debug.startTime.getSeconds());
var mean = diff / n;
alert("Done. Check the result on the page.");
logger.debug.status("One write request takes <b>" + mean + "</b> seconds.<br>Test time: " + diff + " seconds");
},
/**
* @private
*/
processWrite: function (db, i) {
// logger.consoles.original.log("processWrite");
var transaction = db.transaction(["customers"], "readwrite");
// Do something when all the data is added to the database.
transaction.oncomplete = function (event) {
// logger.consoles.original.log("processWrite.transaction.oncomplete");
};
transaction.onerror = function (event) {
// Don't forget to handle errors!
// logger.consoles.original.error("processWrite.transaction.onerror: "+event.code);
};
var objectStore = transaction.objectStore("customers");
var data = { ssn: i, name: "Bill", age: 35, email: "mail" + i + "@rtlservice.com" }
var request = objectStore.put(data);
request.onsuccess = function (event) {
// event.target.result == customerData[i].ssn;
// logger.consoles.original.log("processWrite.transaction...onsuccess: "+event.target.result);
if (i == logger.debug.totalNumberOfWrites - 1) {
logger.debug.testFinished();
}
};
request.onerror = function () {
logger.consoles.original.error("addPublication error", this.error);
}
},
status: function (str) {
document.getElementById(logger.debug.statusElementId).innerHTML = str;
}
}
}

View File

@ -3,3 +3,4 @@ export * from './libs/comty_ng/pre.js';
export * from './libs/yulio_id/pre.js';
export * from './libs/app_functions/pre.js';
export * from './libs/api_call/pre.js';
export * from './libs/apis/pre.js'

View File

@ -0,0 +1 @@
export * from './unsplash.js'

View File

@ -0,0 +1,16 @@
import axios from 'axios'
import * as app from 'app'
import keys from 'keys'
export const api_unsplash = {
search: async (key, callback) => {
if (!key) return false
const response = await axios.get(app.endpoints.unsplash_endpoints.search, {
params: { query: key},
headers: {
Authorization: `Client-ID ${keys.unsplash_key}`
}
})
return callback(response.data.results)
}
}

View File

@ -1,7 +1,7 @@
import React from 'react'
import * as app from 'app'
import * as antd from 'antd'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import styles from './modals.less';
import classnames from 'classnames'
@ -19,12 +19,12 @@ class __Model_postreport extends React.PureComponent {
return false
}
app.notify.info('This post has been reported successfully, our team will review it and inform you about problem resolution ...')
app.FeedHandler.refresh()
app.FeedHandler.goToElement(this.props.id)
app.RenderFeed.RefreshFeed()
app.RenderFeed.goToElement(this.props.id)
}, payload)
}
setTimeout(() => {
app.OverlaySwap.close()
app.SwapMode.close()
}, 500)
}
@ -116,7 +116,7 @@ export const app_modals = {
icon: <Icons.FrownOutlined />,
content: 'It seems that you want to report this post, first of all it is necessary that you take into account that this tool is only intended for serious cases and we need you to comply with some questions to be able to report this post and to guarantee the quality of service ...',
onOk() {
return app.OverlaySwap.openFragment(<__Model_postreport id={post_id} />)
return app.SwapMode.openFragment(<__Model_postreport id={post_id} />)
},
onCancel() {
return false

View File

@ -0,0 +1,82 @@
import { notification } from 'antd'
import * as Icons from 'components/Icons'
export const notify = {
fatal: (...res) => {
notification.error({
message: 'Fatal Error',
icon: <Icons.Triangle style={{ color: '#fa8c16' }} />,
description: res,
placement: 'bottomLeft'
})
},
expire: (...res) => {
notification.error({
message: 'Hey ',
icon: <Icons.FieldTimeOutlined />,
description: res,
placement: 'bottomLeft',
})
},
info: (...res) => {
notification.info({
message: 'Well',
description: res.toString(),
placement: 'bottomLeft',
})
},
exception: (...res) => {
notification.error({
message: 'WoW!',
description: res.toString(),
placement: 'bottomLeft',
})
},
warn: (...res) => {
notification.warn({
message: 'Hey!',
description: res.toString(),
placement: 'bottomLeft',
})
},
success: (...res) => {
notification.success({
message: 'Well',
description: res.toString(),
placement: 'bottomLeft',
})
},
error: (...res) => {
notification.error({
message: 'Wopss',
description: (
<div>
<span>An wild error appear! : </span>
<br />
<br />
<div
style={{
position: 'relative',
width: '100%',
backgroundColor: 'rgba(243, 19, 19, 0.329)',
bottom: '0',
color: 'black',
padding: '3px',
}}
>
{res.toString()}
</div>
</div>
),
placement: 'bottomLeft',
})
},
proccess: (...res) => {
notification.open({
icon: <Icons.LoadingOutlined style={{ color: '#108ee9' }} />,
message: 'Please wait',
description: <div>{res}</div>,
placement: 'bottomLeft',
})
},
}

View File

@ -1,53 +1,21 @@
import { RenderFeed } from 'components/MainFeed'
import { transitionToogle } from '../../../pages/login'
import { SetControls, CloseControls } from 'components/Layout/ControlBar'
import { SwapMode } from 'components/Layout/Overlay'
import umiRouter from 'umi/router'
import * as app from 'app'
import * as antd from 'antd'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import React from 'react'
import { SwapMode } from 'components/Layout/Overlay'
import { RenderFeed } from 'components/MainFeed'
import { updateTheme } from '../../../layouts/PrimaryLayout'
export * from './modals.js'
export * from './notify.js'
export {SwapMode}
export function SetupApp() {
// TODO: Default sets
app.notify.success('Authorised, please wait...')
const resourceLoad = localStorage.getItem('resource_bundle')
if (!resourceLoad) {
localStorage.setItem('resource_bundle', 'light_ng')
}
setTimeout(() => {
app.router.push('main')
}, 500)
}
export const CheckThisApp = {
desktop_mode: () => {
const a = localStorage.getItem('desktop_src')
if (a == 'true') {
return true
}
return false
},
}
export const OverlaySwap = {
close: () => {
SwapMode.close()
},
openPost: e => {
SwapMode.openPost(e)
},
openSearch: e => {
SwapMode.openSearch(e)
},
openFragment: e =>{
SwapMode.openFragment(e)
}
}
export {RenderFeed}
export const ControlBar = {
set: e => {
@ -58,30 +26,6 @@ export const ControlBar = {
},
}
export const FeedHandler = {
refresh: () => {
RenderFeed.RefreshFeed()
},
killByID: (post_id) => {
RenderFeed.killByID(post_id)
},
addToRend: (payload) => {
RenderFeed.addToRend(payload)
},
goToElement: post_id => {
RenderFeed.goToElement(post_id)
},
sync: data => {
RenderFeed.sync(data)
}
}
export const LoginPage = {
transitionToogle: () => {
transitionToogle()
},
}
export const router = {
go: e => {
goTo.element('primaryContent')
@ -118,6 +62,7 @@ export const goTo = {
try {
document.getElementById(element).scrollIntoView()
} catch (error) {
console.debug(error)
return false
}
}
@ -204,3 +149,52 @@ export const app_session = {
},
}
export const app_theme = {
getString: () => {
return localStorage.getItem('theme_style')
},
set: (data, process) => {
if (!data){
return false
}
let newdata = []
if(process){
let style = data
let mix = []
try {
style[key] = value
const obj = Object.entries(style)
obj.forEach((e) => {
mix.push({key: e[0], value: e[1]})
})
newdata = JSON.stringify(mix)
} catch (error) {
console.log(error)
return false
}
}else{
newdata = data
}
localStorage.setItem('theme_style', newdata)
app_theme.update()
},
getStyle: () => {
let final = {}
const storaged = localStorage.getItem('theme_style')
if (storaged) {
try {
let scheme = JSON.parse(storaged)
scheme.forEach((e)=>{
final[e.key] = e.value
})
} catch (error) {
console.log(error)
}
}
return final
},
update: () => {
return updateTheme(app_theme.getStyle())
}
}

View File

@ -1,5 +1,5 @@
import { token_data } from 'app'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
export * from './comty_post.js'
export * from './comty_user.js'

View File

@ -1,11 +0,0 @@
const VerifiedBadge = () => (<svg xmlns="http://www.w3.org/2000/svg" fill="#55acee" width="15" height="15" viewBox="0 0 24 24"> <path d="M23 12l-2.44-2.78.34-3.68-3.61-.82-1.89-3.18L12 3 8.6 1.54 6.71 4.72l-3.61.81.34 3.68L1 12l2.44 2.78-.34 3.69 3.61.82 1.89 3.18L12 21l3.4 1.46 1.89-3.18 3.61-.82-.34-3.68L23 12m-13 5l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z"></path></svg>)
const CommonThings = () => (<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#ff5991" d="M15,2C16.94,2 18.59,2.7 19.95,4.05C21.3,5.41 22,7.06 22,9C22,10.56 21.5,11.96 20.58,13.2C19.64,14.43 18.44,15.27 16.97,15.7L17,15.38V15C17,12.81 16.23,10.93 14.65,9.35C13.07,7.77 11.19,7 9,7H8.63L8.3,7.03C8.73,5.56 9.57,4.36 10.8,3.42C12.04,2.5 13.44,2 15,2M9,8A7,7 0 0,1 16,15A7,7 0 0,1 9,22A7,7 0 0,1 2,15A7,7 0 0,1 9,8M9,10A5,5 0 0,0 4,15A5,5 0 0,0 9,20A5,5 0 0,0 14,15A5,5 0 0,0 9,10Z"></path></svg>)
const SunSVG = () => (<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 21 21"><g fill="none" fillRule="evenodd"><path fill="#fff" fillRule="nonzero" d="M21 10.5l-3 3V18h-4.5l-3 3-3-3H3v-4.5l-3-3 3-3V3h4.5l3-3 3 3H18v4.5z"></path><circle stroke="#000" strokeWidth="1.5" cx="10.5" cy="10.5" r="4"></circle></g></svg>)
const MoonSVG = () => (<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 21 21"><g fill="none" fillRule="evenodd"><circle fill="#fff" cx="10.5" cy="10.5" r="10.5"></circle><path d="M13.396 11c0-3.019-1.832-5.584-4.394-6.566A6.427 6.427 0 0111.304 4C15.002 4 18 7.135 18 11c0 3.866-2.998 7-6.698 7A6.42 6.42 0 019 17.566c2.564-.98 4.396-3.545 4.396-6.566z" fill="#2F2E30" fillRule="nonzero"></path></g></svg>)
const RobotOutlined = () => (<svg viewBox="64 64 896 896" focusable="false" data-icon="robot" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M300 328a60 60 0 10120 0 60 60 0 10-120 0zM852 64H172c-17.7 0-32 14.3-32 32v660c0 17.7 14.3 32 32 32h680c17.7 0 32-14.3 32-32V96c0-17.7-14.3-32-32-32zm-32 660H204V128h616v596zM604 328a60 60 0 10120 0 60 60 0 10-120 0zm250.2 556H169.8c-16.5 0-29.8 14.3-29.8 32v36c0 4.4 3.3 8 7.4 8h729.1c4.1 0 7.4-3.6 7.4-8v-36c.1-17.7-13.2-32-29.7-32zM664 508H360c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h304c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"></path></svg>)
const SavedPost = () => (<svg viewBox="0 0 24 24" focusable="false" width="1em" height="1em" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" ><path d="M4 3h16a2 2 0 0 1 2 2v6a10 10 0 0 1-10 10A10 10 0 0 1 2 11V5a2 2 0 0 1 2-2z"></path><polyline points="8 10 12 14 16 10"></polyline></svg>)
const SavedPostColor = () => (<svg viewBox="0 0 24 24" focusable="false" width="1em" height="1em" fill="rgb(230, 247, 255)" stroke="rgb(24, 144, 255)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" ><path d="M4 3h16a2 2 0 0 1 2 2v6a10 10 0 0 1-10 10A10 10 0 0 1 2 11V5a2 2 0 0 1 2-2z"></path><polyline points="8 10 12 14 16 10"></polyline></svg>)
const SavedPostGrey = () => (<svg viewBox="0 0 24 24" focusable="false" width="1em" height="1em" fill="rgb(196, 196, 196)" stroke="rgba(133, 133, 133, 1)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" ><path d="M4 3h16a2 2 0 0 1 2 2v6a10 10 0 0 1-10 10A10 10 0 0 1 2 11V5a2 2 0 0 1 2-2z"></path><polyline points="8 10 12 14 16 10"></polyline></svg>)
const CustomIcons = {SavedPostGrey, SavedPostColor, VerifiedBadge, CommonThings, SunSVG, MoonSVG, RobotOutlined, SavedPost}
export default CustomIcons

View File

@ -3,7 +3,7 @@ import * as antd from 'antd'
import * as app from 'app'
import styles from './index.less'
import classnames from 'classnames'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
export const SetHeaderSearchType = {
disable: () => {

View File

@ -0,0 +1,8 @@
export const VerifiedBadge = () => (<svg xmlns="http://www.w3.org/2000/svg" fill="#55acee" width="15" height="15" viewBox="0 0 24 24"> <path d="M23 12l-2.44-2.78.34-3.68-3.61-.82-1.89-3.18L12 3 8.6 1.54 6.71 4.72l-3.61.81.34 3.68L1 12l2.44 2.78-.34 3.69 3.61.82 1.89 3.18L12 21l3.4 1.46 1.89-3.18 3.61-.82-.34-3.68L23 12m-13 5l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z"></path></svg>)
export const Patreon = () => (<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 100 96">
<g fill="currentColor" fill-rule="evenodd">
<path d="M64.1102,0.1004 C44.259,0.1004 28.1086,16.2486 28.1086,36.0986 C28.1086,55.8884 44.259,71.989 64.1102,71.989 C83.9,71.989 100,55.8884 100,36.0986 C100,16.2486 83.9,0.1004 64.1102,0.1004"/>
<polygon points=".012 95.988 17.59 95.988 17.59 .1 .012 .1"/>
</g>
</svg>
)

View File

@ -0,0 +1,4 @@
export * from 'feather-reactjs'
export * from '@ant-design/icons'
export * from './custom'

View File

@ -1,6 +1,6 @@
import * as React from 'react'
import * as antd from 'antd'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import styles from '../index.less'
export interface Card_Component_props {

View File

@ -1,6 +1,6 @@
import * as React from 'react'
import * as antd from 'antd'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import styles from '../../index.less'
import classnames from 'classnames'
import reactable from 'reactablejs'

View File

@ -1,7 +1,7 @@
import * as React from 'react'
import * as app from 'app'
import * as antd from 'antd'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import styles from '../../index.less'
import classnames from 'classnames'
import reactable from 'reactablejs'

View File

@ -11,7 +11,7 @@
border: 0!important;
outline: 0!important;
color: #273346;
padding: 0 48px;
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;
background-size: 16px;

View File

@ -3,34 +3,12 @@ import styles from './__priPost.less'
import * as antd from 'antd'
import * as app from 'app'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import Icon from '@ant-design/icons'
import { MediaPlayer } from 'components'
const VerifiedBadge = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="#55acee"
width="15"
height="15"
viewBox="0 0 24 24"
>
<path d="M23 12l-2.44-2.78.34-3.68-3.61-.82-1.89-3.18L12 3 8.6 1.54 6.71 4.72l-3.61.81.34 3.68L1 12l2.44 2.78-.34 3.69 3.61.82 1.89 3.18L12 21l3.4 1.46 1.89-3.18 3.61-.82-.34-3.68L23 12m-13 5l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z"></path>
</svg>
)
import { MediaPlayer, PostCard } from 'components'
export default class __priPost extends React.PureComponent {
renderContent(payload) {
const { id, postText, postFile_full, post_time, publisher } = payload
const {isMobile}= this.props
return (
<div className={styles.contentWrapper}>
{postFile_full ? <MediaPlayer isMobile={isMobile} entire={true} file={postFile_full} /> : null}
</div>
)
}
render() {
const {payload} = this.props
@ -38,23 +16,13 @@ export default class __priPost extends React.PureComponent {
return <h1>This post not exists!!!</h1>
}
const { id, postText, postFile_full, post_time, publisher } = payload
const {isMobile}= this.props
return (
<div className={styles.render_component}>
<div className={styles.UserContainer}>
<div className={styles.UserContainer_text}>
<h4 className={styles.titleUser}>
{publisher.username}{' '}
{app.booleanFix(publisher.verified) ? (
<Icon style={{ color: 'blue' }} component={VerifiedBadge} />
) : null}
</h4>
<p>
{post_time} {app.IsThisUser.dev() ? `| #${id}` : null}{' '}
</p>
</div>
<antd.Avatar shape="square" size={50} src={publisher.avatar} />
<div className={styles.contentWrapper}>
<div className={styles.contentBody}>
<PostCard id="post_card" payload={payload} key={id} />
</div>
{this.renderContent(payload)}
</div>
)
}

View File

@ -1,33 +1,27 @@
@import '~themes/index.less';
.contentWrapper {
margin: auto;
width: 100%;
padding: 20px;
height: 100%;
position: absolute;
top: 0;
left: 0;
align-items: center;
margin: auto;
background: rgba(158, 158, 158, 0.5); // Make sure this color has an opacity of less than 1
backdrop-filter: blur(10px); // This be the blur
display: flex;
align-items: center;
transition: all @__Global_SwapAnimDuration ease-in-out;
}
.contentBody{
.UserContainer {
display: flex;
position: relative;
float: right;
z-index: 150;
transform: translate(0, -40px);
.UserContainer_text {
margin: 0 8px;
h4 {
text-align: right;
}
p {
word-break: break-all;
text-align: right;
font-size: 11px;
color: #eeeeee !important;
}
}
}
width: calc(100% - @Overlay_container2_active_width);
}

View File

@ -72,16 +72,18 @@ export default class __priSearch extends React.PureComponent {
}
}
EntryComponent = (t, source) => {
function onclick(e){
function goToEntry(e){
if(!e) return false
app.router.go(`@${e}`)
}
try {
return (
<antd.List
dataSource={source}
renderItem={item =>
<div id={item.id} className={styles.search_card} onClick={() => onclick(item.username) }>
<div id={item.id} className={styles.search_card} onClick={() => goToEntry(item.username) }>
<div className={styles.search_title}>
<img src={item.avatar} />
<p className={styles.search_user_username}>

View File

@ -4,7 +4,7 @@ import { SearchCard, Feather } from 'components'
import * as antd from 'antd'
import * as app from 'app'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import Icon from '@ant-design/icons'
const VerifiedBadge = () => (

View File

@ -1,7 +1,7 @@
import React from 'react'
import * as app from 'app'
import * as antd from 'antd'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import styles from './index.less'
import classnames from 'classnames'
import reactable from 'reactablejs'
@ -111,7 +111,7 @@ export const SwapMode = {
<h2>
<Icons.SearchOutlined /> Results of {id || '... nothing ?'}
</h2>
<__priSearch lost_focus={() => SwapMode.close()} payload={tmp} />
<__priSearch payload={tmp} />
</div>
return OverlayLayoutComponent.setState({

View File

@ -51,12 +51,12 @@
.Overlay_wrapper {
right: 0;
top: 0;
overflow: hidden;
z-index: 50;
height: 100vh;
width: 100%;
max-width: @Overlay_wrapper_maxwidth;
// 150px extra for left-sider
width: calc( 100% + 150px );
backdrop-filter: blur(2px);
&.mobile{
overflow-y: scroll;
flex-direction: column;
@ -67,14 +67,15 @@
position: absolute;
width: 100%;
height: 100%;
max-width: none;
width: none;
}
}
&.expand{
max-width: calc(@Overlay_wrapper_maxwidth + 150px);
max-width: calc(100% + 150px);
}
transition: all @__Global_SwapAnimDuration ease-in-out;
}
@ -82,25 +83,40 @@
height: 100%;
width: 100%;
max-width: @Overlay_wrapper_maxwidth;
min-width: 200px;
display: flex;
z-index: 50;
right: 0;
padding: 30px 30px 30px 35px;
@media (max-width: @bp-medium) {
padding: 30px 5px 30px 5px;
}
color: @Overlay_container1_def_color;
background-color: #F8F6F8;
&.half {
background-color: #2d2d2d;
color: @Overlay_container1_active_color;
max-width: calc(100% + 150px);
}
&.full_open {
width: @Overlay_wrapper_showFull_width;
max-width: none;
background-color: transparent;
position: absolute;
width: 100vw;
height: 100vh;
}
&.mobile {
min-width: unset;
max-width: unset;
width: 100%;
height: 0;
bottom: 0;

View File

@ -1,22 +1,77 @@
import React from 'react'
import * as antd from 'antd'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import Icon from '@ant-design/icons'
import { withI18n, Trans } from '@lingui/react'
import styles from './default.less'
import * as app from 'app'
import CustomIcons from '../../CustomIcons'
import classnames from 'classnames'
@withI18n()
export default class Sider_Default extends React.PureComponent {
state = {
loading: true,
menus: null
}
require(e){
switch (e) {
case 'login':
return true
case 'admin':
return true
default:
return true
}
}
componentDidMount(){
try {
let tmp = [];
const { menus } = this.props
menus.forEach(e => {
if (this.require(e.require)) {
tmp.push(e)
}
});
this.setState({ menus: tmp, loading: false })
} catch (error) {
console.log(error)
}
}
renderMenus(data){
try {
return data.map(e => {
return(
<antd.Menu.Item key={e.id}>
{e.icon}
<Trans>
<span>{e.title}</span>
</Trans>
</antd.Menu.Item>
)
})
} catch (error) {
console.log(error)
return null
}
}
render() {
const { handleClickMenu, logo } = this.props
const { handleClickMenu, logo, theme } = this.props
const predominantColor = theme.predominantColor || "#333"
if (this.state.loading) return <div>Loading</div>
return (
<div className={styles.left_sider_wrapper}>
<antd.Layout.Sider
trigger={null}
className={styles.left_sider_container}
style={{ flex:'unset', maxWidth: 'unset', minWidth: '200px', width: '100%'}}
>
<div className={styles.left_sider_brandholder}>
<img
@ -28,40 +83,14 @@ export default class Sider_Default extends React.PureComponent {
<div className={styles.left_sider_menuContainer}>
<antd.Menu
selectable={false}
// style={{color: predominantColor}}
//className={classnames(styles.left_sider_menuItems, {[styles.matchColor]: theme.predominantColor? true : false})}
selectable={true}
className={styles.left_sider_menuItems}
mode="vertical"
onClick={handleClickMenu}
>
<antd.Menu.Item key="explore">
<Icons.CompassTwoTone twoToneColor={"#28c35d"} />
<Trans>
<span>Explore</span>
</Trans>
</antd.Menu.Item>
<antd.Menu.Item key="saves">
<Icon component={CustomIcons.SavedPostColor} />
<Trans>
<span>Saves</span>
</Trans>
</antd.Menu.Item>
<antd.Menu.Item key="marketplace">
<Icons.ShoppingTwoTone twoToneColor={"#ff7a45"}/>
<Trans>
<span>Marketplace</span>
</Trans>
</antd.Menu.Item>
<antd.Menu.Item key="chats">
<Icons.MessageTwoTone twoToneColor={"#ff4d4f"}/>
<Trans>
<span>Chats</span>
</Trans>
</antd.Menu.Item>
{this.renderMenus(this.state.menus)}
</antd.Menu>
@ -69,8 +98,9 @@ export default class Sider_Default extends React.PureComponent {
<antd.Menu
selectable={false}
className={styles.left_sider_menuItems}
mode="horizontal"
mode="vertical"
onClick={handleClickMenu}
>
<antd.Menu.Item key="general_settings">
<Icons.SettingOutlined />

View File

@ -5,36 +5,68 @@
border-color: transparent;
font-size: 13px;
font-family: @__Global_general_font_family;
width: 100%;
height: 100vh;
z-index: 40;
float: left;
position: relative;
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: @left_sider_backgroud;
background-color: transparent;
float: right;
.ant-menu {
vertical-align: middle;
margin: 0 0 0 5px;
// margin: 0 0 0 5px;
}
.ant-menu-item {
color: #333;
transition: @transition-ease-inout;
border-radius: 4px 8px 8px 4px;
padding: 2px 0 2px 24px;
text-align: left;
}
.ant-menu-item:hover {
border-radius: 8px 8px 8px 8px;
transform: translate(10px,0);
// 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;
color: rgb(102, 102, 102);
}
.ant-menu-item-selected {
background-color: unset;
// background: linear-gradient(90deg, rgb(255, 230, 0) 2%, rgba(255,255,255,0.5) 10%);
}
.anticon {
font-size: @left_sider_sizeIcons;
}
.ant-menu-inline-collapsed,
.antd-menu-vertical-left,
.ant-menu-vertical {
:hover {
background-color: @left_sider_menu__onhover_backgroud;
color: @left_sider_menu__onhover_color;
}
border-right: 0 solid transparent;
}
}
@ -45,14 +77,11 @@
.left_sider_brandholder {
cursor: pointer;
img {
display: flex;
vertical-align: middle;
padding: 5px;
margin: 7px auto 15px auto;
width: 100%;
max-height: 58px;
transform: translate(2px, 0);
img{
margin: 7px 0 0 20px;
max-height: 70px;
height: 7vh;
filter: drop-shadow(1px 0px 1px #b9b9b9);
}
}
@ -68,9 +97,8 @@
}
.ant-menu-item{
height: 35px!important;
line-height: 0px!important;
padding: 0!important;
margin: 0!important;
margin-bottom: 0!important;
line-height: 30px;
}
}
}
@ -84,8 +112,6 @@
.left_sider_menuContainer {
height: 100%;
margin: 18px 0 8px 0;
overflow-x: hidden;
flex: 1;
:global {
@ -126,12 +152,5 @@
animation: fadein 0.5s;
:global {
.ant-menu-item {
padding: 0 !important;
margin: 2px auto 2px 24px;
width: 100%;
text-align: left;
}
}
}

View File

@ -1,50 +1,28 @@
import React from 'react'
import config from 'config'
import * as app from 'app'
import MenuList from 'globals/sidebar_menu'
import Sider_Mobile from './mobile.js'
import Sider_Default from './default.js'
class Sider extends React.PureComponent {
onClickFunctions = {
saves: (e) => {
this.setState({selectedKey: e})
app.router.go('saves')
},
events: (e) => {
this.setState({selectedKey: e})
app.router.go('events')
},
marketplace: (e) => {
this.setState({selectedKey: e})
app.router.go('marketplace')
},
explore: (e) => {
this.setState({selectedKey: e})
app.router.go('main')
},
chats: (e) => {
this.setState({selectedKey: e})
app.router.go('chats')
}
}
handleClickMenu = e => {
e.key === 'chats' && this.onClickFunctions.chats(e.key)
e.key === 'messages' && app.router.go('messages')
e.key === 'SignOut' && app.app_session.logout()
e.key === 'general_settings' && app.router.go('settings')
e.key === 'profile' && app.router.goprofile()
e.key === 'saves' && this.onClickFunctions.saves(e.key)
e.key === 'events' && this.onClickFunctions.events(e.key)
e.key === 'marketplace' && this.onClickFunctions.marketplace(e.key)
e.key === 'explore' && this.onClickFunctions.explore(e.key)
e.key === 'debug_area' && app.router.go('__m')
e.key === 'saves' && app.router.go('saves')
e.key === 'main' && app.router.go('main')
e.key === 'explore' && app.router.go('explore')
e.key === 'notifications' && app.router.go('notifications')
e.key === 'debug_area' && app.router.go('debug')
}
render() {
const { isMobile } = this.props
const sider_props = {handleClickMenu: this.handleClickMenu ,logo: config.LogoPath, menulist: null, userData: this.props.userData}
const { isMobile, theme } = this.props
const sider_props = {theme: theme, menus: MenuList, handleClickMenu: this.handleClickMenu ,logo: config.LogoPath, menulist: null, userData: this.props.userData}
if (isMobile) {
return <Sider_Mobile {...sider_props} />

View File

@ -1,12 +1,12 @@
import React from 'react'
import * as antd from 'antd'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import Icon from '@ant-design/icons'
import { withI18n, Trans } from '@lingui/react'
import styles from './mobile.less'
import * as app from 'app'
import CustomIcons from '../../CustomIcons'
@withI18n()
export default class Sider_Mobile extends React.PureComponent {

View File

@ -125,6 +125,7 @@ class MainFeed extends React.PureComponent {
more(fkey){
try {
const { get, uid, filters } = this.props
console.log(get)
if (!get) {
app.yconsole.error('Please, fill params with an catch type...')
return
@ -154,7 +155,7 @@ class MainFeed extends React.PureComponent {
return true
}, payload)
} catch (err) {
app.notify.error(err)
app.notify.error('[ MainFeed ]', err)
}
}
}

View File

@ -1,9 +1,9 @@
import React from 'react'
import * as antd from 'antd'
import styles from './index.less'
import { CustomIcons, Like_button, MediaPlayer } from 'components'
import { Like_button, MediaPlayer } from 'components'
import * as Icons from 'components/Icons'
import * as app from 'app'
import * as Icons from '@ant-design/icons'
import Icon from '@ant-design/icons'
import classnames from 'classnames'
import * as MICON from '@material-ui/icons'
@ -11,11 +11,21 @@ import * as MICON from '@material-ui/icons'
const { Meta } = antd.Card
// Set default by configuration
const emptyPayload = {
user: 'Post Empty',
ago: 'This Post is empty',
avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
content: 'Empty',
const defaultPayload = {
id: null,
post_time: null,
postText: null,
postFile: null,
publisher: null,
post_likes: null,
is_post_pinned: null,
is_liked: null,
post_comments: null,
get_post_comments: null,
postPinned: false,
postReported: false,
postBoosted: false,
ReportIgnore: false,
}
class PostCard extends React.PureComponent {
@ -23,13 +33,36 @@ class PostCard extends React.PureComponent {
super(props),
this.state = {
visibleMoreMenu: false,
postPinned: this.props.payload.is_post_pinned,
postSaved: this.props.payload.is_post_saved,
postReported: this.props.payload.is_post_reported,
postBoosted: this.props.payload.is_post_boosted,
ReportIgnore: false,
payload: this.props.payload,
}
}
componentDidMount(){
const a = this.props.payload
const b = defaultPayload
try {
if(a){
let tmp;
const propsArray = Object.keys(a)
const defaultArray = Object.keys(b)
propsArray.forEach(e => {
if (defaultArray.includes(e)){
tmp[e] = "something"
}
})
console.log(tmp)
}
else{
console.warn('Empty payload, setting default...')
this.setState({ payload: b})
}
} catch (error) {
}
}
handleVisibleChange = flag => {
this.setState({ visibleMoreMenu: flag });
};
@ -39,10 +72,9 @@ class PostCard extends React.PureComponent {
}
render() {
const { payload, customActions } = this.props
const { payload } = this.state
const ActShowMode = app.AppSettings.auto_hide_postbar
const post_data = payload || emptyPayload;
const {
id,
post_time,
@ -54,14 +86,17 @@ class PostCard extends React.PureComponent {
is_liked,
post_comments,
get_post_comments
} = post_data
} = payload || defaultPayload
if(!id, !postText, !postFile, !publisher) return null
const SwapThisPost = () => {
localStorage.setItem('p_back_uid', id)
if (postFile){
app.SwapMode.openPost(id, post_data)
}
app.SwapMode.openPost(id, payload)
app.SwapMode.openComments(id)
}
const handlePostActions = {
@ -71,7 +106,7 @@ class PostCard extends React.PureComponent {
if (err) {
return false
}
app.FeedHandler.killByID(post_id)
app.RenderFeed.killByID(post_id)
}, payload)
},
save: post_id => {
@ -110,7 +145,7 @@ class PostCard extends React.PureComponent {
}, payload)
},
}
const defaultActions = [
const actions = [
<div>
<Like_button
count={post_likes}
@ -123,7 +158,6 @@ class PostCard extends React.PureComponent {
<MICON.InsertComment key="comments" onClick={() => SwapThisPost()} />
</antd.Badge>,
]
const actions = customActions || defaultActions
const MoreMenu = (
<antd.Menu >
@ -223,7 +257,7 @@ class PostCard extends React.PureComponent {
{app.booleanFix(publisher.verified) ? (
<Icon
style={{ color: 'blue' }}
component={CustomIcons.VerifiedBadge}
component={Icons.VerifiedBadge}
/>
) : null}
{app.booleanFix(publisher.nsfw_flag) ? (

View File

@ -2,7 +2,7 @@ import React from 'react'
import * as antd from 'antd'
import * as app from 'app'
import styles from './index.less'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import Icon from '@ant-design/icons'
import $ from 'jquery'
import * as MICONS from '@material-ui/icons'
@ -155,7 +155,7 @@ class PostCreator extends React.PureComponent {
setTimeout(() => {
this.setState({ posting_ok: false })
}, 1000)
app.FeedHandler.refresh()
app.RenderFeed.RefreshFeed()
return true
}
@ -220,7 +220,7 @@ class PostCreator extends React.PureComponent {
)
}
this.FlushPostState()
// app.FeedHandler.addToRend(JSON.parse(res)['data'])
// app.RenderFeed.addToRend(JSON.parse(res)['data'])
}, payload)
}
dropRef = React.createRef()

View File

@ -1,7 +1,7 @@
import React from 'react'
import * as antd from 'antd'
import * as app from 'app'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import Icon from '@ant-design/icons'
import { Post_Options } from 'globals/post_options.js'
import styles from './post_options.less'

View File

@ -2,8 +2,7 @@ import React from 'react'
import styles from './styles.less'
import * as app from 'app'
import * as antd from 'antd'
import { CustomIcons, MainFeed, PostCreator } from 'components'
import * as Icons from '@ant-design/icons'
import { Icons, MainFeed, PostCreator } from 'components'
import Icon from '@ant-design/icons'
import Follow_btn from './components/Follow_btn.js'
import { BadgesType } from 'globals/badges_list'
@ -199,7 +198,7 @@ className={classnames(styles.userWrapper, {
color: 'blue',
verticalAlign: 'top',
}}
component={CustomIcons.VerifiedBadge}
component={Icons.VerifiedBadge}
/>
) : null}
</antd.Tooltip>

View File

@ -1,7 +1,7 @@
// @alias from 'components'
// Helpers & Misc
import CustomIcons from './CustomIcons'
export * as Icons from './Icons'
import Loader from './Loader/Loader.js'
import App_about from './App_about'
import * as Feather from 'feather-reactjs'
@ -35,7 +35,6 @@ export {
Loader,
PostCard,
PostCreator,
CustomIcons,
Like_button,
MainFeed,
}

View File

@ -21,13 +21,21 @@ import styles from './PrimaryLayout.less'
const { Content } = antd.Layout
const { Sider, Control, Overlay, WindowAppBar } = MyLayout
export function updateTheme(data){
if (!data) return false
console.log(data)
return PrimaryComponent.setState({theme: data})
}
@withRouter
@connect(({ app, loading }) => ({ app, loading }))
class PrimaryLayout extends React.Component {
class PrimaryLayout extends React.PureComponent {
constructor(props) {
super(props)
window.PrimaryComponent = this
this.state = {
theme: app.app_theme.getStyle(),
collapsed: app.AppSettings.default_collapse_sider ? true : false,
isMobile: false,
desktop_mode: false,
@ -36,6 +44,7 @@ class PrimaryLayout extends React.Component {
}
componentDidMount() {
this.setState({
userData: app.userData(),
})
@ -62,12 +71,22 @@ class PrimaryLayout extends React.Component {
}
render() {
const { app, location, dispatch, children } = this.props
const { userData, collapsed, isMobile } = this.state
const { location, dispatch, children } = this.props
const { userData, collapsed, isMobile, theme, predominantColor } = this.state
const { onCollapseChange } = this
const { theme } = app
const SiderProps = {
breakpoint:{
xs: '480px',
sm: '576px',
md: '768px',
lg: '992px',
xl: '1200px',
xxl: '1600px',
},
predominantColor,
theme,
userData,
isMobile,
@ -85,13 +104,13 @@ class PrimaryLayout extends React.Component {
userData,
isMobile,
}
console.log(theme)
return (
<React.Fragment>
<div className={classnames(styles.__ControlBar, {[styles.mobile]: isMobile})}>
<Control mobile={isMobile} />
</div>
<antd.Layout id="primaryLayout" className={classnames(styles.primary_layout, {[styles.mobile]: isMobile})}>
<antd.Layout style={theme} id="primaryLayout" className={classnames(styles.primary_layout, {[styles.mobile]: isMobile})}>
<Sider {...SiderProps} />
<div className={styles.primary_layout_container}>

View File

@ -12,16 +12,24 @@
}
.primary_layout {
background-repeat: repeat-x;
background-size: cover;
background-position-y: center;
overflow: hidden;
background-color: @primary_layout_backgroud;
background-color: transparent;
margin: auto;
height: 100vh;
width: 100vw;
transition: all @__Global_Components_transitions_dur linear;
&.mobile{
>.primary_layout_container {
border-radius: 0;
margin: 0;
padding: 0;
overflow-y: overlay;
overflow-x: hidden;
min-width: unset;
}
.primary_layout_content{
padding: 35px 15px 15px 15px;
@ -31,25 +39,40 @@
// PRIMARY LAYOUT
.primary_layout_container {
transition: background-color @__Global_layout_transitions-dur linear;
background-color: @primary_layout_container_backgroud;
border-radius: @primary_layout_container_border-rd;
background-color: transparent;
transition: all @__Global_Components_transitions_dur linear;
overflow-x: hidden;
margin: 0 0 0 10px;
width: 100vw;
// overflow-y: overlay;
width: auto;
height: 100vh;
position: relative;
bottom: 0;
display: flex;
align-self: center;
float: left;
max-width: 750px;
min-width: 570px;
@media (min-width: @bp-medium) {
min-width: 650px;
}
@media (min-width: @bp-large) {
min-width: 850px;
}
}
.primary_layout_content {
vertical-align: middle;
width: 100%;
float: right;
padding: @primary_layout_content_padding;
transition: all @__Global_layout_transitions-dur ease;
@media (max-width: @bp-medium) {
padding: 0;
}
}

View File

@ -1,3 +1,67 @@
export default ({ children }) => {
return children
import React from 'react'
import store from 'store'
import {
MyLayout,
PageTransition,
} from 'components'
import { enquireScreen, unenquireScreen } from 'enquire-js'
import classnames from 'classnames'
import * as antd from 'antd'
import * as Icons from 'components/Icons'
import styles from './PrimaryLayout.less'
const { Content } = antd.Layout
export default class PublicLayout extends React.Component {
constructor(props) {
super(props)
window.PrimaryComponent = this
this.state = {
isMobile: false,
}
}
componentDidMount() {
this.enquireHandler = enquireScreen(mobile => {
const { isMobile } = this.state
if (isMobile !== mobile) {
this.setState({
isMobile: mobile,
})
store.set('mobile_src', mobile)
}
})
}
componentWillUnmount() {
unenquireScreen(this.enquireHandler)
}
render() {
const { children } = this.props
const { isMobile } = this.state
return (
<React.Fragment>
<antd.Layout id="publicLayout" className={classnames(styles.primary_layout, {[styles.mobile]: isMobile})}>
<div className={styles.primary_layout_container}>
<PageTransition
preset="moveToRightScaleUp"
transitionKey={window.location.pathname}
>
<Content
id="publicContent"
className={styles.primary_layout_content}
>
{children}
</Content>
</PageTransition>
</div>
</antd.Layout>
</React.Fragment>
)
}
}

View File

@ -1,7 +1,7 @@
/* global window */
import { router } from 'utils'
import store from 'store'
import { pathMatchRegexp } from 'utils'
import { pathMatchRegexp, queryLayout } from 'utils'
import config from 'config'
import * as app from 'app'
@ -42,23 +42,23 @@ export default {
},
effects: {
*query({ payload }, { call, put, select }) {
// if (queryLayout(config.layouts, window.location.pathname) == 'public') {
// return true
// }
const validBackup = app.validate.backup()
if (app.validate.session() == true) {
if (pathMatchRegexp(['/', '/login'], window.location.pathname)) {
router.push({ pathname: '/main' })
router.push({ pathname: `${config.MainPath}` })
}
app._app.query()
return true
} else if (!pathMatchRegexp(['', '/login'], window.location.pathname)) {
} else if (!pathMatchRegexp(['', '/login'], window.location.pathname) && queryLayout(config.layouts, window.location.pathname) !== 'public') {
if (validBackup == true) {
app._app.logout()
} else {
router.push({ pathname: '/login' })
}
}
if (pathMatchRegexp([''], window.location.pathname)) {
router.push({ pathname: '/login' })
}
},
},
reducers: {

21
src/pages/debug/index.js Normal file
View File

@ -0,0 +1,21 @@
import React from 'react'
import * as app from 'app'
export default class Debug extends React.Component{
render(){
return(
<>
<div>Debug</div><hr/>
<button onClick={() => app.notify.fatal('Error test! sike')} >Send Critical error</button>
<button onClick={() => {
}}> start storage logs </button>
<button onClick={() =>{
app.logger.download();
}}> Download logs </button>
</>
)
}
}

View File

@ -3,7 +3,9 @@ import * as app from 'app'
class Index extends PureComponent {
render() {
app.router.go(`login`)
return(
<div></div>
)
}
}

View File

@ -4,7 +4,7 @@ import styles from './index.less'
import classnames from 'classnames'
import * as antd from 'antd'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import { RegistrationForm } from './register.js'
import { NormalLoginForm } from './login.js'

View File

@ -94,7 +94,6 @@ export class NormalLoginForm extends React.PureComponent {
switch (res) {
case '200': {
this.anim_transition(300)
app.LoginPage.transitionToogle()
return
}
case '400': {

View File

@ -6,10 +6,10 @@ import styles from './index.less'
export default class Main extends React.Component {
render() {
return (
<div className={styles.mainWrapper}>
<>
<PostCreator userData={app.userData()} />
<MainFeed auto={true} get="feed" />
</div>
</>
)
}
}

View File

@ -1,6 +1,2 @@
@import '~themes/index.less';
.mainWrapper {
position: relative;
padding: 20px;
}

View File

@ -7,7 +7,7 @@ import MessageInput from '../messages/MessageInput'
import * as app from 'app'
import * as antd from 'antd'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import styles from '../styles.less'
import classnames from 'classnames'

View File

@ -1,7 +1,7 @@
import React from 'react'
import * as app from 'app'
import * as antd from 'antd'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import io from 'socket.io-client'
import config from 'config'
import ReactEmoji from 'react-emoji';
@ -19,6 +19,7 @@ export default class Chats extends React.Component{
super(props);
this.state = {
err_tick: 0,
socket:null,
user:null,
conn: false
@ -40,7 +41,7 @@ export default class Chats extends React.Component{
console.log(prefix, "Connected");
const payload = { id: userData.UserID, name: userData.username, avatar: userData.avatar }
socket.emit(USER_CONNECTED, payload);
this.setState({user: payload, conn: true})
this.setState({user: payload, conn: true, err_tick: 0})
})
}
@ -51,13 +52,19 @@ export default class Chats extends React.Component{
})
socket.on('reconnecting', () =>{
console.log(prefix, 'Trying to reconnect')
this.setState({ err_tick: (this.state.err_tick+1) })
console.log(prefix, 'Trying to reconnect', this.state.err_tick)
})
}
render() {
const { socket, user } = this.state
if(!user) return <div ><h1>Loading</h1></div>
if( this.state.err_tick > 2) return <antd.Result
status="500"
title="You're offline"
subTitle="It seems that you are disconnected and could not connect to the server."
/>
if(!user) return <div style={{ backgroundColor: '#fff', borderRadius: '10px', padding: '20px', marginTop: '50px' }}><h1> <Icons.LoadingOutlined spin /> Connecting to server...</h1><antd.Skeleton active /></div>
return <ChatContainer socket={socket} user={user} />
}

View File

@ -2,7 +2,7 @@ import React from 'react'
import { pathMatchRegexp } from 'utils'
import * as app from 'app'
import * as antd from 'antd'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
export default class Indexer_Post extends React.Component {
constructor(props) {
@ -20,7 +20,7 @@ export default class Indexer_Post extends React.Component {
if (err) {
return false
}
app.OverlaySwap.openPost(res)
app.SwapMode.openPost(res)
}, payload)
}

View File

@ -0,0 +1,9 @@
import React from 'react'
export default class TestPublic extends React.Component{
render(){
return(
<div>Test your Publics!</div>
)
}
}

View File

@ -0,0 +1,13 @@
import React from 'react'
import config from 'config'
export default class PAGE_PUBLIC extends React.Component{
render(){
return(
<div>
<img src={config.DarkFullLogoPath} /> <h1>Style Design</h1>
</div>
)
}
}

View File

@ -1,7 +1,7 @@
import React from 'react'
import * as app from 'app'
import * as antd from 'antd'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import { MainFeed } from 'components'
import styles from './index.less'

View File

@ -1,9 +1,32 @@
import React from 'react'
import { App_about } from 'components'
import l from 'globals/links'
import * as Icons from 'components/Icons'
import * as antd from 'antd'
export default class AppAbout extends React.Component {
render() {
return <App_about />
return <>
<App_about />
<antd.Card>
<div>
<h4>🎉 It's completely free and open source !</h4>
<h5>It is an impressive amount of work and effort, help us to continue offering quality services, you can support us from our patreon campaign.</h5>
<a href={l.patreon}><Icons.Patreon/> Support us with Patreon!</a>
</div>
<antd.Divider dashed />
<div>
<h4>👨💻 You are developer? You can help us by joining our team!</h4>
<a href={l.gitlab}><Icons.Gitlab />Official Repository</a><br />
<a href={l.github}><Icons.GitHub />Mirror Repository</a><br />
<a href={l.trellojoin}><Icons.Trello />Join our Trello</a>
</div>
</antd.Card>
</>
}
}

View File

@ -3,9 +3,8 @@ import { List, Switch, Button, notification, InputNumber } from 'antd'
import { ListSettings } from '../../../../globals/settings.js'
import { ControlBar } from 'app'
import * as app from 'app'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import Icon from '@ant-design/icons'
import { CustomIcons } from 'components'
class Base extends Component {
constructor(props) {

View File

@ -1,7 +1,7 @@
import React from 'react'
import * as app from 'app'
import * as antd from 'antd'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
export default class Earnings extends React.Component {

View File

@ -0,0 +1,9 @@
import React from 'react'
export default class Help extends React.Component{
render(){
return <>
</>
}
}

View File

@ -1,6 +1,6 @@
import React from 'react'
import * as app from 'app'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import styles from './index.less'
export default class NotificationView extends React.Component {

View File

@ -1,6 +1,6 @@
import React from 'react'
import * as app from 'app'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import * as antd from 'antd'
import styles from './index.less'

View File

@ -0,0 +1,230 @@
import React from 'react'
import * as Feather from 'feather-reactjs'
import * as app from 'app'
import * as antd from 'antd'
import { SketchPicker } from 'react-color';
import ColorThief from 'colorthief/dist/color-thief'
var colorThief = new ColorThief();
class BackgroundColor extends React.Component{
state = {
selected: "#fff"
}
sendChanges(){
this.props.changeColor(this.state.selected)
}
selectColor = (color) =>{
this.setState({selected: color.hex})
}
render(){
return <>
<SketchPicker
color={this.state.selected}
onChangeComplete={this.selectColor}
/>
<antd.Button onClick={() => this.sendChanges()}> Change </antd.Button>
</>
}
}
class BackgroundImage extends React.Component{
state = {
results: []
}
search(key){
if (!key) return false
app.api_unsplash.search(key, (res) =>{
console.log(res)
this.setState({ results: res })
})
}
returnString(url){
this.props.selectImg(`url(${url})`)
}
render(){
return (
<>
<h3> <Feather.Image /> Upload </h3>
<antd.Divider type="horizontal" dashed />
<h3> 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>) }/>
</>
)
}
}
export default class ThemeSettings extends React.PureComponent{
state = {
helper_visible: false,
helper_fragment: null,
style: [],
}
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 {
const storaged = JSON.parse(app.app_theme.getString())
let mix = {};
storaged.forEach((e)=>{
return e.key !== key? mix[e.key] = e.value : null
})
console.log(mix)
this.encode(mix, (res)=> {
app.app_theme.set(res)
this.decodeData()
})
} catch (error) {
console.log(error)
return false
}
}
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 })
},
close: () => {
this.setState({ helper_visible: false, helper_fragment: null })
},
backgroundImage: () => {
this.helper.open(<BackgroundImage selectImg={(i) => this.handleChanges("backgroundImage", i)} />)
},
backgroundColor: () => {
this.helper.open(<BackgroundColor changeColor={(i) => this.handleChanges("backgroundColor", i)} />)
}
}
render(){
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>
<antd.Drawer
title="Theme Settings"
placement="right"
width="500"
closable={true}
onClose={this.helper.close}
visible={this.state.helper_visible}
>
<React.Fragment>
{this.state.helper_fragment}
</React.Fragment>
</antd.Drawer>
</div>
)
}
}

View File

@ -1,6 +1,8 @@
import React from 'react'
import { Menu } from 'antd'
import * as Icons from '@ant-design/icons'
import * as Icons from 'components/Icons'
import * as Feather from 'feather-reactjs'
import styles from './style.less'
import NotificationView from './components/notification/index.js'
@ -9,6 +11,7 @@ import Earnings from './components/earnings/index.js'
import Base from './components/base.js'
import AppAbout from './components/about.js'
import Theme from './components/theme'
const { Item } = Menu
const menuMap = {
@ -17,6 +20,11 @@ const menuMap = {
<Icons.ControlOutlined /> General
</span>
),
theme: (
<span>
<Feather.Layers /> Theme
</span>
),
sync: (
<span>
<Icons.SyncOutlined /> Sync
@ -24,12 +32,12 @@ const menuMap = {
),
security: (
<span>
<Icons.SafetyCertificateOutlined /> Security & Privacity
<Feather.Lock /> Security & Privacity
</span>
),
notification: (
<span>
<Icons.MailOutlined /> Notification
<Feather.Bell /> Notification
</span>
),
earnings: (
@ -37,9 +45,14 @@ const menuMap = {
<Icons.DollarCircleOutlined /> Earnings
</span>
),
help: (
<span>
<Icons.LifeBuoy /> Help
</span>
),
about: (
<span>
<Icons.ContainerOutlined /> About
<Feather.Info /> About
</span>
),
}
@ -71,6 +84,8 @@ class GeneralSettings extends React.Component {
return <Base />
case 'security':
return <SecurityView />
case 'theme':
return <Theme />
case 'notification':
return <NotificationView />
case 'about':
@ -89,7 +104,7 @@ class GeneralSettings extends React.Component {
<div className={styles.main}>
<div className={styles.leftMenu}>
<h2>
<Icons.SettingOutlined /> Settings{' '}
<Icons.SettingOutlined /> Settings
</h2>
<Menu
mode="inline"

View File

@ -14,7 +14,6 @@
.leftMenu {
width: 224px;
:global {
.ant-menu-inline {
color: @__Global_layout_color;

View File

@ -8,6 +8,8 @@
@import './components/PostCard.less';
@__Global_backgroud_image: "";
@__Global_general_font_family: "Poppins", sans-serif;
@__Global_texted_font: "Manrope", sans-serif;
@__Global_alternative_font: "Netflix Sans";
@ -20,10 +22,14 @@
@__Global_SwapAnimDuration: 170ms;
@__Global_backdrop_backgroud: rgba(158, 158, 158, 0.5);
@transition-ease-in: all 0.3s ease-out;
@transition-ease-out: all 0.3s ease-out;
@ease-in: ease-in;
@transition-ease-inout: all 150ms ease-in-out;
@Overlay_wrapper_hidden_width: 22vw;
@ -75,8 +81,11 @@ body {
line-height: @base-line-height;
font-family: @__Global_texted_font;
}
background-color: @primary_layout_backgroud;
}
@media (max-width: @bp-small){
::-webkit-scrollbar{
@ -93,15 +102,11 @@ body {
}
@media (min-width: @bp-xlarge) {
body{
zoom: 1.4;
}
}
@media (min-width: @bp-xxlarge) {
body{
zoom: 1.6;
}
}

View File

@ -1,8 +1,8 @@
@import '~themes/index.less';
// .left_sider*
@left_sider_backgroud: #F8F6F8;
@left_sider_color: #fff;
@left_sider_color: #333;
@left_sider_sizeIcons: 19px;
@left_sider_menu__onhover_backgroud: rgb(80, 80, 80);
@left_sider_menu__onhover_color: #fff;
@left_sider_menu__onhover_color: rgb(80, 80, 80);

View File

@ -5,5 +5,5 @@
@primary_layout_container_backgroud: @__Global_layout_backgroud;
@primary_layout_container_border-rd: @__Global_layout_border-rd;
@primary_layout_content_padding: 35px 25px 15px 40px;
@primary_layout_content_padding: 25px;

View File

@ -247,9 +247,11 @@ export const _app = {
app.notify.success('Authorised, please wait...')
const resourceLoad = localStorage.getItem('resource_bundle')
if (!resourceLoad) {
localStorage.setItem('resource_bundle', 'light_ng')
localStorage.setItem('resource_bundle', 'comtyng_default')
}
app.router.push('main')
setTimeout(() => {
app.router.push('main')
}, 420)
},
query: () => {
const validBackup = app.validate.backup()

32
test/login.test.js Normal file
View File

@ -0,0 +1,32 @@
import puppeteer from 'puppeteer'
describe('Login', () => {
let browser
let page
beforeAll(async () => {
browser = await puppeteer.launch({ args: ['--no-sandbox'] })
})
beforeEach(async () => {
page = await browser.newPage()
await page.goto('http://localhost:8000/en/login', {
waitUntil: 'networkidle2',
})
})
afterEach(() => page.close())
it('should login with failure', async () => {
await page.waitFor(selector => !!document.querySelector('#username'), {
timeout: 3000,
})
await page.type('#username', 'wrong_user')
await page.type('#password', 'wrong_password')
await page.click('button[type="button"]')
await page.waitForSelector('.anticon-close-circle') // should display error
})
afterAll(() => browser.close())
})