update: posts components & contextual menus

This commit is contained in:
srgooglo 2020-09-17 02:40:42 +02:00
parent 9622b7718c
commit 2ed0835232
21 changed files with 873 additions and 126 deletions

View File

@ -2,6 +2,8 @@ export default {
auth_server: 'POST /auth_server', auth_server: 'POST /auth_server',
auth: 'POST /auth', auth: 'POST /auth',
sessions: 'POST /sessions', sessions: 'POST /sessions',
posts: 'POST /posts',
post_actions: 'POST /post-actions',
get_data: 'POST /get-user-data', get_data: 'POST /get-user-data',
profileData: 'POST /early_user' profileData: 'POST /early_user'

View File

@ -51,15 +51,14 @@ module.exports = {
search_ontype: false, search_ontype: false,
overlay_loosefocus: true, overlay_loosefocus: true,
render_pagetransition_preset: 'moveToRightScaleUp', render_pagetransition_preset: 'moveToRightScaleUp',
post_catchlimit: '20',
post_hidebar: true,
feed_autorefresh: false, feed_autorefresh: false,
}, },
stricts: { stricts: {
post_maxlenght: '512', post_maxlenght: '512',
post_catchlimit: '20',
post_hidebar: true,
// In KB // In KB
api_maxpayload: '101376', api_maxpayload: '101376',
api_maxovertick: 10, api_maxovertick: 10,

View File

@ -4,6 +4,7 @@ const {
ipcMain, ipcMain,
Tray, Tray,
Menu, Menu,
MenuItem,
dialog, dialog,
shell, shell,
screen, screen,
@ -18,7 +19,7 @@ const log = require('electron-log');
const packagejson = require('../package.json') 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');
let app_path = is.dev()? 'http://127.0.0.1:8000/' : `file://${path.join(__dirname, '..', 'renderer')}/index.html`; let app_path = is.dev()? 'http://127.0.0.1:8000/' : `file://${path.join(__dirname, '..', 'renderer')}/index.html`;
let mainWindow; let mainWindow;
@ -28,7 +29,7 @@ let watcher;
// This gets rid of this: https://github.com/electron/electron/issues/13186 // This gets rid of this: https://github.com/electron/electron/issues/13186
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true
// app.commandLine.appendSwitch("disable-web-security") // app.commandLine.appendSwitch("disable-web-security")
app.commandLine.appendSwitch('disable-gpu-vsync=gpu') //app.commandLine.appendSwitch('disable-gpu-vsync=gpu')
app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors') app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors')
const gotTheLock = app.requestSingleInstanceLock() const gotTheLock = app.requestSingleInstanceLock()
@ -40,6 +41,23 @@ if (!gotTheLock) {
app.quit(); app.quit();
} }
function contextualMenu(cords){
if (!cords) {
return false
}
log.log(cords)
const menu = new Menu()
const menuItem = new MenuItem({
label: 'Inspect Element',
click: () => {
mainWindow.inspectElement(cords.x, cords.y)
}
})
menu.append(menuItem)
menu.popup(mainWindow)
}
function notify(params) { function notify(params) {
if(!notifySupport || !params) return false if(!notifySupport || !params) return false
let options = { let options = {
@ -249,3 +267,8 @@ ipcMain.handle('appRestart', () => {
ipcMain.handle('app_notify', (payload) => { ipcMain.handle('app_notify', (payload) => {
notify(payload) notify(payload)
}) })
ipcMain.handle('contextualMenu', (payload) => {
log.log(payload)
contextualMenu(payload)
})

View File

@ -3,7 +3,7 @@
"UUID": "C8mVSr-4nmPp2-pr5Vrz-CU4kg4", "UUID": "C8mVSr-4nmPp2-pr5Vrz-CU4kg4",
"title": "Comty™", "title": "Comty™",
"DevBuild": true, "DevBuild": true,
"version": "0.9.09", "version": "0.9.17",
"stage": "dev-pre", "stage": "dev-pre",
"description": "", "description": "",
"author": "RageStudio", "author": "RageStudio",
@ -32,21 +32,21 @@
}, },
"dependencies": { "dependencies": {
"@icons-pack/react-simple-icons": "^3.8.0", "@icons-pack/react-simple-icons": "^3.8.0",
"@lingui/cli": "^2.9.1", "@lingui/react": "^2.9.2",
"@lingui/loader": "^2.9.1",
"@lingui/react": "^2.9.1",
"@material-ui/core": "^4.9.9", "@material-ui/core": "^4.9.9",
"@material-ui/icons": "^4.9.1", "@material-ui/icons": "^4.9.1",
"@ragestudio/ycorejs-lib": "^0.1.22", "@ragestudio/ycorejs-lib": "^0.1.22",
"antd": "^4.6.1", "antd": "^4.6.4",
"axios": "^0.19.2", "axios": "^0.19.2",
"babel-core": "^6.26.3", "babel-core": "^6.26.3",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"cookie_js": "^1.4.0", "cookie_js": "^1.4.0",
"electron-config": "^2.0.0", "electron-config": "^2.0.0",
"electron-context-menu": "^2.3.0",
"electron-is": "^3.0.0", "electron-is": "^3.0.0",
"electron-log": "^4.2.4", "electron-log": "^4.2.4",
"electron-notification-state": "^1.0.4", "electron-notification-state": "^1.0.4",
"electron-remote": "^1.3.0",
"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",
@ -55,7 +55,7 @@
"less-vars-to-js": "^1.3.0", "less-vars-to-js": "^1.3.0",
"localforage": "^1.7.4", "localforage": "^1.7.4",
"lodash": "^4.17.19", "lodash": "^4.17.19",
"moment": "^2.27.0", "moment": "^2.28.0",
"node-sass": "^4.13.1", "node-sass": "^4.13.1",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"path-to-regexp": "^6.1.0", "path-to-regexp": "^6.1.0",
@ -78,36 +78,37 @@
"redux-socket.io": "^1.4.0", "redux-socket.io": "^1.4.0",
"redux-thunk": "^2.3.0", "redux-thunk": "^2.3.0",
"request": "^2.88.2", "request": "^2.88.2",
"simple-icons": "^3.3.0", "simple-icons": "^3.8.0",
"slash": "^3.0.0", "slash": "^3.0.0",
"socket.io-client": "^2.3.0", "socket.io-client": "^2.3.0",
"stack-trace": "0.0.10", "stack-trace": "0.0.10",
"store": "^2.0.12", "store": "^2.0.12",
"styled-components": "^5.1.1", "styled-components": "^5.2.0",
"timeago.js": "^4.0.2", "timeago.js": "^4.0.2",
"wait-on": "^5.2.0" "wait-on": "^5.2.0"
}, },
"devDependencies": { "devDependencies": {
"@lingui/babel-preset-react": "^2.9.0", "@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@lingui/cli": "^2.9.0", "@lingui/babel-preset-react": "^2.9.2",
"@lingui/loader": "^2.9.0", "@lingui/cli": "^2.9.2",
"@umijs/preset-react": "^1.4.0", "@lingui/loader": "^2.9.2",
"electron": "^10.1.0", "@types/electron-devtools-installer": "^2.2.0",
"electron-debug": "^2.0.0", "@types/node": "^12.12.59",
"electron-rebuild": "^1.7.3", "@umijs/preset-react": "^1.6.5",
"electron-builder": "^22.8.0",
"electron-devtools-installer": "^3.1.1",
"concurrently": "^3.5.1",
"babel-eslint": "^10.0.1", "babel-eslint": "^10.0.1",
"babel-plugin-dev-expression": "^0.2.1", "babel-plugin-dev-expression": "^0.2.1",
"babel-plugin-module-resolver": "^4.0.0", "babel-plugin-module-resolver": "^4.0.0",
"concurrently": "^3.5.1",
"cross-env": "^6.0.0", "cross-env": "^6.0.0",
"dva-model-extend": "^0.1.2", "dva-model-extend": "^0.1.2",
"electron": "^10.1.2",
"electron-builder": "^22.8.0",
"electron-debug": "^2.0.0",
"electron-devtools-installer": "^3.1.1",
"electron-rebuild": "^1.7.3",
"electron-reloader": "^1.0.1",
"jsdoc": "^3.6.5", "jsdoc": "^3.6.5",
"typescript": "^3.8.3", "typescript": "^3.8.3",
"umi": "^3.2.19", "umi": "^3.2.20"
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@types/electron-devtools-installer": "^2.2.0",
"@types/node": "^12.12.52"
} }
} }

View File

@ -1,10 +1,21 @@
<svg id="e9915989-cca6-4620-8282-9db0f616b757" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 120"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 74.31418 77.6027" style="opacity: 90%">
<defs>
<clipPath id="a" transform="translate(-62.852 -42.79726)">
<path d="M67.69373,97.48126A37.88848,37.88848,0,0,1,64.32235,81.962V51.74457a8,8,0,0,1,8-8h30.81344A40.20284,40.20284,0,0,1,115.504,45.80379V60.70226H99.244v5.1882a17.26642,17.26642,0,0,0-12.40516,13.0078H80.273v18.583Z" style="fill: none"/>
</clipPath>
</defs>
<g>
<path <path
d="M77.55,29.69,92,18.78a1.42,1.42,0,0,0,.25-2,39.2,39.2,0,0,0-56.31-4.21A38.05,38.05,0,0,0,23.23,42a38.09,38.09,0,0,0,3.62,15.1A38.65,38.65,0,0,0,37.8,70.84,39.46,39.46,0,0,0,83.37,73a38.26,38.26,0,0,0,8.41-7.4,1.41,1.41,0,0,0-.23-2L77.65,53a1.43,1.43,0,0,0-1.9.15A17,17,0,0,1,72.55,56a17.75,17.75,0,0,1-9,2.88c-8.32.31-13.62-5.69-14-6.13a17.68,17.68,0,0,1-4.13-10.13,17.93,17.93,0,0,1,4.56-13A17.46,17.46,0,0,1,71.7,26.34a17.3,17.3,0,0,1,4,3.2A1.41,1.41,0,0,0,77.55,29.69Z" d="M120.3477,73.49586l16.068-8.392a1.421,1.421,0,0,0,.581-1.925l-.004-.009a39.55488,39.55488,0,0,0-53.655-14.202q-.636.369-1.259.763a37.94591,37.94591,0,0,0-16.316,42.476,38.68947,38.68947,0,0,0,8.549,15.373,39.509,39.509,0,0,0,44.645,9.645,38.33887,38.33887,0,0,0,9.525-5.922,1.41255,1.41255,0,0,0,.121-1.993l-.019-.02-11.979-12.759a1.4336,1.4336,0,0,0-1.902-.165,17.03956,17.03956,0,0,1-3.628,2.287,17.77554,17.77554,0,0,1-9.363,1.361c-8.267-1.065-12.512-7.864-12.815-8.361a17.70265,17.70265,0,0,1-2.409-10.684,17.95939,17.95939,0,0,1,6.646-12.087,17.73033,17.73033,0,0,1,24.61,3.044c.283.361.549.734.802,1.117a1.413,1.413,0,0,0,1.802.453"
style="fill: rgba(51, 51, 51, 0.80);" transform="translate(-62.852 -42.79726)"
/> style="fill: #333333"/>
<path <g style="clip-path: url(#a)">
d="M13,63.17a2.77,2.77,0,0,1,3.75,1.43A48.38,48.38,0,0,0,32.07,84.53,48.83,48.83,0,0,0,52.34,93.3,47.37,47.37,0,0,0,92.57,81.8a2.77,2.77,0,0,1,4,.3l6.23,7.4a2.79,2.79,0,0,1-.21,3.83,63.83,63.83,0,0,1-6,5,62.21,62.21,0,0,1-7.44,4.7A60.84,60.84,0,0,1,77,108a62.3,62.3,0,0,1-27,1.51A62.51,62.51,0,0,1,40.18,107,61.5,61.5,0,0,1,20.1,95.69,61.73,61.73,0,0,1,2.41,71a2.79,2.79,0,0,1,1.42-3.55Z" <rect width="17.421" height="17.905" style="fill: #333333"/>
style="fill: rgba(51, 51, 51, 0.80);" <rect x="17.421" width="18.971" height="17.905" style="fill: #333333"/>
/> <rect x="36.392" width="16.26" height="17.905" style="fill: #333333"/>
<rect y="17.905" width="17.421" height="18.196" style="fill: #333333"/>
<rect y="36.101" width="17.421" height="18.583" style="fill: #333333"/>
<rect x="17.421" y="17.905" width="18.971" height="18.196" style="fill: #333333"/>
</g>
</g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -2,7 +2,10 @@ import 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 styles from './index.less' import styles from './index.less'
import classnames from 'classnames'
import { connect } from 'umi'
@connect(({ app }) => ({ app }))
export default class Sider_Default extends React.PureComponent { export default class Sider_Default extends React.PureComponent {
state = { state = {
loading: true, loading: true,
@ -27,8 +30,20 @@ export default class Sider_Default extends React.PureComponent {
}) })
} }
HeaderIconRender = () => {
if(this.props.app.session_valid){
return(
<antd.Avatar shape="circle" size="large" src={this.props.app.session_data.avatar} />
)
}else{
return(
<img className={styles.logotype} src={this.props.logo} />
)
}
}
render() { render() {
const { handleClickMenu, logo } = this.props const { handleClickMenu } = this.props
return this.state.loading? null : ( return this.state.loading? null : (
<div className={styles.left_sider_wrapper}> <div className={styles.left_sider_wrapper}>
<antd.Layout.Sider <antd.Layout.Sider
@ -37,11 +52,8 @@ export default class Sider_Default extends React.PureComponent {
width="175px" width="175px"
style={{ flex:'unset', maxWidth: 'unset', minWidth: '175px', width: '100%'}} style={{ flex:'unset', maxWidth: 'unset', minWidth: '175px', width: '100%'}}
> >
<div className={styles.left_sider_header}> <div onClick={() => {handleClickMenu({key: ''})}} className={classnames(styles.left_sider_header, {[styles.emb]: this.props.app.embedded})}>
<img <img className={styles.logotype} src={this.props.logo} />
onClick={() => handleClickMenu({key: ''})}
src={logo}
/>
</div> </div>
<div className={styles.left_sider_menuContainer}> <div className={styles.left_sider_menuContainer}>

View File

@ -71,12 +71,19 @@
.left_sider_header { .left_sider_header {
cursor: pointer; cursor: pointer;
img{
margin: 15px 0 0 22px; margin: 15px 0 0 22px;
.logotype{
max-height: 70px; max-height: 70px;
height: 5vh; height: 35px;
width: 5vh; }
&.emb{
margin: 5px 0 0 22px;
}
&.logged{
} }
} }

View File

@ -1,4 +1,5 @@
@import '~theme/index.less'; @import '~theme/index.less';
@aumentSize: 10px;
.navbar{ .navbar{
-webkit-app-region: drag; -webkit-app-region: drag;
@ -10,12 +11,13 @@
z-index: 5000; z-index: 5000;
top: 0; top: 0;
right: 0; right: 0;
background-color: rgba(54, 54, 54, 0); background-color: rgba(54, 54, 54, 0.1);
transition: all 150ms ease-in-out; transition: all 150ms ease-in-out;
} }
.navbar:hover{ .navbar:hover{
background-color: rgba(54, 54, 54, 0.658); background-color: rgba(54, 54, 54, 0.65);
height: calc(@AppTheme_global_winavbar_height + @aumentSize);
} }
.controls{ .controls{
@ -25,15 +27,17 @@
float: right; float: right;
width: auto; width: auto;
margin: auto; margin: auto;
height: 100%;
> div{ > div{
padding: 0 14px; padding: 0 14px;
svg{ svg{
margin: 0!important; margin: 0!important;
padding: 0; padding: 0;
height: 100%;
} }
} }
> div:hover{ > div:hover{
background-color: rgba(54, 54, 54, 0.808); background-color: rgba(54, 54, 54, 0.8);
color: #fdfdfd; color: #fdfdfd;
} }
transition: all 150ms ease-in-out; transition: all 150ms ease-in-out;

View File

@ -0,0 +1,53 @@
import React from 'react'
import styles from './like.less'
import * as core from 'core'
import classnames from 'classnames'
export default class LikeBtn extends React.Component {
state = {
liked: this.props.liked,
count: this.props.count,
clicked: false,
}
render() {
const { id } = this.props
const { count, liked, clicked } = this.state
return (
<div className={styles.btnWrapper}>
<button className={classnames(styles.like_button, {[styles.clickanim]: clicked })} >
<div className={styles.like_wrapper}>
<div
className={classnames(
styles.ripple,
liked ? null : { [styles.clickanim]: clicked }
)}
></div>
<svg
className={classnames(
styles.heart,
{ [styles.empty]: !liked },
liked ? null : { [styles.clickanim]: clicked }
)}
width="24"
height="24"
viewBox="0 0 24 24"
>
<path d="M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z"></path>
</svg>
</div>
</button>
<p
className={classnames(styles.likeCounter, {
[styles.active]: !clicked,
[styles.past]: clicked,
})}
>
{count}
</p>
</div>
)
}
}

View File

@ -0,0 +1,205 @@
.like_button,
.like_button:before,
.like_button:after {
position: relative;
box-sizing: border-box;
}
.ripple,
.ripple:before,
.ripple:after {
position: relative;
box-sizing: border-box;
}
.btnWrapper {
display: flex;
}
.likeCounter {
font-family: "Poppins", sans-serif;
line-height: 70px;
margin: 0 0 0 10px;
opacity: 0;
transform: perspective(100px) translateZ(10px);
filter: blur(10px);
letter-spacing: 0.1em;
&.active {
opacity: 1;
transform: perspective(100px) translateZ(0px);
filter: blur(0px);
letter-spacing: 0.15em;
transition: opacity 1000ms linear, transform 1000ms linear, filter 400ms linear, letter-spacing 1000ms linear;
}
&.past {
opacity: 0;
transform: perspective(100px) translateZ(-10px);
filter: blur(10px);
letter-spacing: 0.2em;
transition: opacity 1000ms linear, transform 1000ms linear, filter 400ms linear, letter-spacing 1000ms linear;
}
}
.like_button {
--color-heart: #EA442B;
--easing: cubic-bezier(.7, 0, .3, 1);
--duration: .5s;
font-size: 40px;
border: none;
border-radius: 50%;
background: white;
width: 1em;
height: 1em;
padding: 0;
margin: 0;
outline: none;
z-index: 2;
transition: transform var(--duration) var(--easing);
cursor: pointer;
&:before {
z-index: -1;
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: inherit;
transition: inherit;
}
&:after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #fff;
border-radius: inherit;
z-index: -1;
}
@keyframes depress {
from,
to {
transform: none;
}
50% {
transform: translateY(5%) scale(0.9);
}
}
@keyframes depress-shadow {
from,
to {
transform: none;
}
50% {
transform: scale(0.5);
}
}
}
.like_wrapper {
display: grid;
align-items: center;
justify-content: center;
z-index: 1;
>* {
margin: auto;
grid-area: 1 / 1;
}
}
.heart {
width: .5em;
height: .5em;
display: block;
transform-origin: center 80%;
>path {
stroke: var(--color-heart);
stroke-width: 2;
transition: fill var(--duration) var(--easing);
fill: var(--color-heart);
}
&.empty {
>path {
stroke: var(--color-heart);
stroke-width: 2;
transition: fill var(--duration) var(--easing);
fill: transparent;
}
}
&.clickanim {
animation: heart-bounce var(--duration) var(--easing);
@keyframes heart-bounce {
40% {
transform: scale(0.7);
}
0%,
80%,
100% {
transform: scale(1);
}
}
}
animation: none;
}
.ripple {
height: 1em;
width: 1em;
border-radius: 50%;
overflow: hidden;
z-index: 1;
&:before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: .4em solid var(--color-heart);
border-radius: inherit;
transform: scale(0);
}
&.clickanim {
&:before {
animation: ripple-out var(--duration) var(--easing);
@keyframes ripple-out {
from {
transform: scale(0);
}
to {
transform: scale(5);
}
}
}
}
}

View File

@ -0,0 +1,161 @@
import React from 'react'
import * as antd from 'antd'
import styles from './index.less'
import { MediaPlayer } from 'components'
import * as Icons from 'components/Icons'
import * as core from 'core'
import Icon from '@ant-design/icons'
import classnames from 'classnames'
import settings from 'core/libs/settings'
import { router } from 'core/cores'
import LikeBtn from './components/like'
import { connect } from 'umi'
const { Meta } = antd.Card
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,
}
@connect(({ app }) => ({ app }))
export default class PostCard extends React.Component {
state = {
visibleMoreMenu: false,
payload: this.props.payload,
}
handleDispatchInvoke(key, payload) {
this.props.dispatch({
type: "app/ipcInvoke",
payload: { key: key, payload: payload }
})
}
toogleMoreMenu(){
this.setState({ visibleMoreMenu: !this.state.visibleMoreMenu })
}
handleActions(){
}
renderReportedPost(){
if(this.state.ReportIgnore) return null
return (
<div className={styles.post_card_flaggedWarning}>
<Icons.FlagOutlined />
<h3>It seems that this post has been reported</h3>
<p>The content may be inappropriate or compromising</p>
<antd.Button
onClick={() => {
this.setState({ ReportIgnore: true })
}}
>
Ignore
</antd.Button>
</div>
)
}
renderPost(data){
const {
id,
post_time,
postText,
postFile,
publisher,
post_likes,
is_post_pinned,
is_liked,
post_comments,
get_post_comments
} = data || defaultPayload
return(
<>
{this.state.postReported? this.renderReportedPost() : null}
<div className={classnames(styles.post_include, {[styles.blur]: this.state.ReportIgnore? false : this.state.postReported })}>
<Meta
avatar={
<div className={styles.postAvatar}>
<antd.Avatar shape="square" size={50} src={publisher.avatar} />
</div>
}
title={
<div className={styles.post_card_title}>
<h4 onClick={() => router.go(`@${publisher.username}`)} className={styles.titleUser}>
@{publisher.username}
{core.booleanFix(publisher.verified)? (<Icon style={{ color: 'blue' }} component={Icons.VerifiedBadge} />) : null}
{core.booleanFix(publisher.nsfw_flag)? (<antd.Tag style={{ margin: '0 0 0 13px' }} color="volcano" > NSFW </antd.Tag> ) : null}
</h4>
<div className={styles.PostTags}>
<div className={styles.MoreMenu}>
<antd.Dropdown onVisibleChange={this.handleVisibleChange} visible={this.state.visibleMoreMenu} trigger={['click']}>
<Icons.MoreOutlined key="actionMenu" />
</antd.Dropdown>
</div>
{core.booleanFix(is_post_pinned)? (<Icons.PushpinFilled />) : null}
</div>
</div>
}
description={<span className={styles.textAgo}>{post_time}</span>}
bordered="false"
/>
{postText ? (
<div className={styles.post_card_content}>
<h3 dangerouslySetInnerHTML={{ __html: postText }} />
</div>
) : null}
{postFile ? (
<div className={styles.post_card_file}>
<MediaPlayer file={postFile} />
</div>
) : null}
<div className={styles.ellipsisIcon}>
<Icons.EllipsisOutlined />
</div>
</div>
</>
)
}
render() {
const handleContextMenu = e => this.handleDispatchInvoke("contextualMenu", {cords: {x: e.clientX, y: e.clientY} })
const actions = [
<LikeBtn count={this.state.payload.post_likes} liked={core.booleanFix(this.state.payload.is_liked)} />,
<Icons.Share2 />,
<antd.Badge dot={this.state.payload.post_comments > 0 ? true : false}>
<Icons.MessageSquare key="comments" />
</antd.Badge>,
]
return (
<div className={styles.post_card_wrapper}>
<antd.Card
className={settings("post_hidebar") ? null : styles.showMode}
onDoubleClick={() => null}
onClick={this.handleClick}
onContextMenu={handleContextMenu}
actions={actions}
hoverable
>
{this.renderPost(this.state.payload)}
</antd.Card>
</div>
)
}
}

View File

@ -0,0 +1,231 @@
@import '~theme/index.less';
.post_card_flaggedWarning {
border-radius: @post_card_general_border-rd;
width: 100%;
text-align: center;
position: absolute;
z-index: 20;
background: @post_card_flaggedWarning_backgroud;
font-family: @__Global_general_font_family;
padding: @post_card_flaggedWarning_padding;
:global {
.anticon {
font-size: @post_card_flaggedWarning_iconSize;
}
}
}
.post_card_wrapper {
box-shadow: @post_card_wrapper_shadow;
border-radius: @post_card_general_border-rd;
max-width: 510px;
min-width: 265px;
width: auto;
margin: 23px auto 50px auto;
:global {
.ant-card-meta-detail>div:not(:last-child) {
margin: 0
}
.ant-card {
border-radius: @post_card_general_border-rd;
border: 0;
border-top: 1px solid #4646460c;
}
.ant-card-body {
padding: 0;
}
.ant-card-actions {
border-top: 0;
background: @post_card_wrapper_actions_backgroud;
height: 30px;
position: relative;
transition: opacity @__Global_Components_transitions_dur linear, position @__Global_Components_transitions_dur linear, transform @__Global_Components_transitions_dur linear;
border-radius: 0 0 10px 10px;
opacity: 0;
&.showMode {
opacity: 1;
transform: translate(0, 15px);
}
}
.ant-card-actions:hover {
opacity: 1;
transform: translate(0, 15px);
transition: opacity @__Global_Components_transitions_dur linear, position @__Global_Components_transitions_dur linear, transform @__Global_Components_transitions_dur linear;
}
.ant-card-actions>li>.anticon {
font-size: 16px;
line-height: 22px;
width: 40px;
height: 40px;
background: @post_card_wrapper_actions_icon_backgroud;
border-radius: 23px;
}
.ant-card-actions>li {
margin: -20px 0 0 0;
border-right: 0;
.ant-badge-count {
width: 20px;
text-align: left;
span {
font-size: 12px;
}
.ant-scroll-number-only>p.ant-scroll-number-only-unit {
height: 20px;
width: 20px;
margin: 0;
line-height: 20px;
padding: 0 0 0 1px;
}
}
span {
font-size: 16px;
line-height: 22px;
width: 40px;
height: 40px;
background: @post_card_wrapper_actions_icon_backgroud;
border-radius: 23px;
margin: auto;
}
svg {
height: 20px;
width: 20px;
height: 100%;
vertical-align: middle;
}
#feather_icon{ margin-right: unset!important; }
}
}
}
.post_include {
padding: 13px 0 5px 0;
transition: all 150ms linear;
&.blur {
filter: blur(10px);
}
}
.showMode {
:global {
ul {
opacity: 1 !important;
transform: translate(0, 15px);
}
}
}
.post_card_title {
display: flex;
h4 {
cursor: pointer;
}
}
.postAvatar {
position: absolute;
left: -8px;
top: -8px;
display: flex;
}
.titleUser {
display: flex;
font-family: @__Global_general_font_family;
margin: 0 0 0 50px;
}
.textAgo {
display: flex;
font-size: 10px;
margin: 0 0 0 53px;
}
.PostTags {
float: right;
width: 100%;
z-index: 10;
:global {
.anticon {
color: @post_card_wrapper_tags_color_default;
float: right;
margin: -0 6px 0 0;
font-size: 17px;
}
}
}
.post_card_content {
word-break: break-all;
display: flex;
border-radius: 3px;
margin: 23px 24px 23px 24px;
h3 {
font-family: @__Global_general_font_family;
color: @post_card_wrapper_post_content_color;
font-weight: @post_card_wrapper_post_content_weight;
font-size: @post_card_wrapper_post_content_fontSize;
letter-spacing: @post_card_wrapper_post_content_letterSpacing;
}
}
.post_card_file {
display: flex;
margin: 23px 0 5px 0;
max-height: 600px;
overflow: hidden;
h3 {
color: rgb(85, 85, 85);
font-weight: 470;
}
}
.likebtn {
:global {
svg {
color: rgba(0, 0, 0, 0.45);
}
svg:hover {
color: rgb(233, 35, 68);
transition: all 0.2s linear;
}
}
}
.ellipsisIcon {
color: rgba(0, 0, 0, 0.45);
width: 100%;
position: absolute;
text-align: center;
margin: auto;
font-size: 30px;
transition: opacity 150ms linear;
}
.ellipsisIcon:hover {
opacity: 0;
transition: opacity 150ms linear;
}

View File

@ -42,9 +42,7 @@ const PrivacyList = [
@connect(({ app }) => ({ app })) @connect(({ app }) => ({ app }))
class PostCreator extends React.PureComponent { class PostCreator extends React.PureComponent {
constructor(props) { state = {
super(props),
this.state = {
maxFileSize: stricts.api_maxpayload, maxFileSize: stricts.api_maxpayload,
maxTextLenght: stricts.post_maxlenght, maxTextLenght: stricts.post_maxlenght,
@ -60,8 +58,6 @@ class PostCreator extends React.PureComponent {
uploader: false, uploader: false,
uploaderFile: null, uploaderFile: null,
uploaderFileOrigin: null, uploaderFileOrigin: null,
},
window.PostCreatorComponent = this
} }
dropRef = React.createRef() dropRef = React.createRef()
@ -69,9 +65,11 @@ class PostCreator extends React.PureComponent {
ToogleUploader() { ToogleUploader() {
this.setState({ uploader: !this.state.uploader }) this.setState({ uploader: !this.state.uploader })
} }
handleDeleteFile = () => { handleDeleteFile = () => {
this.setState({ uploaderFile: null }) this.setState({ uploaderFile: null })
} }
handleFileUpload = info => { handleFileUpload = info => {
if (info.file.status === 'uploading') { if (info.file.status === 'uploading') {
this.setState({ loading: true }) this.setState({ loading: true })
@ -133,7 +131,6 @@ class PostCreator extends React.PureComponent {
} }
componentDidMount() { componentDidMount() {
// Validate for render
if (this.props.app.session_data) { if (this.props.app.session_data) {
this.setState({renderValid: true}) this.setState({renderValid: true})
} }
@ -253,9 +250,10 @@ class PostCreator extends React.PureComponent {
} }
const PostCreatorComponent = () => { if(!this.state.renderValid) return null
return ( return (
<> <div className={styles.cardWrapper}>
<antd.Card bordered="false">
<div ref={this.dropRef} className={styles.inputWrapper}> <div ref={this.dropRef} className={styles.inputWrapper}>
{this.state.uploader ? <PostCreator_Uploader /> : <PostCreator_InputText /> } {this.state.uploader ? <PostCreator_Uploader /> : <PostCreator_InputText /> }
</div> </div>
@ -285,7 +283,7 @@ class PostCreator extends React.PureComponent {
{this.state.uploader ? ( {this.state.uploader ? (
<Icons.xCicle style={{ margin: 0 }} /> <Icons.xCicle style={{ margin: 0 }} />
) : ( ) : (
<Icons.Plus style={{ margin: 0 }} /> <Icons.Plus style={{ margin: 0, fontSize: '14px' }} />
)} )}
</antd.Button> </antd.Button>
<antd.Button type="ghost" onClick={() => null}> <antd.Button type="ghost" onClick={() => null}>
@ -298,15 +296,6 @@ class PostCreator extends React.PureComponent {
</a> </a>
</antd.Dropdown> </antd.Dropdown>
</div> </div>
</>
)
}
if(!this.state.renderValid) return null
return (
<div className={styles.cardWrapper}>
<antd.Card bordered="false">
<PostCreatorComponent />
</antd.Card> </antd.Card>
</div> </div>
) )

View File

@ -158,7 +158,9 @@
height: 100%; height: 100%;
position: relative; position: relative;
margin: 0 0 40px; margin: 0 0 40px;
svg {
vertical-align: -0.125em;
}
.shareWith { .shareWith {
color: rgb(53, 53, 53); color: rgb(53, 53, 53);
float: right; float: right;

View File

@ -16,10 +16,12 @@ import PageTransition from './PageTransition'
// Post Components // Post Components
import MediaPlayer from './MediaPlayer' import MediaPlayer from './MediaPlayer'
import PostCreator from './PostCreator' import PostCreator from './PostCreator'
import PostCard from './PostCard'
// Mix & Export all // Mix & Export all
export { export {
AppLayout, AppLayout,
PostCard,
Invalid, Invalid,
Icons, Icons,
Feather, Feather,

View File

@ -29,6 +29,7 @@ export default {
overlayActive: false, overlayActive: false,
overlayElement: null, overlayElement: null,
embedded: false,
controlActive: false, controlActive: false,
feedOutdated: false, feedOutdated: false,
@ -42,8 +43,10 @@ export default {
setup({ dispatch }) { setup({ dispatch }) {
try { try {
const electron = window.require("electron") const electron = window.require("electron")
dispatch({ type: 'updateState', payload: { electron: electron } })
dispatch({ type: 'updateState', payload: { electron, embedded: true } })
} catch (error) { } catch (error) {
console.log(error)
// nothing // nothing
} }
uri_resolver().then(res => { uri_resolver().then(res => {
@ -92,6 +95,7 @@ export default {
yield put({ type: 'handleUpdateData' }) yield put({ type: 'handleUpdateData' })
} }
// if (session) { // if (session) {
// if (pathMatchRegexp(['/', '/login'], window.location.pathname)) { // if (pathMatchRegexp(['/', '/login'], window.location.pathname)) {
// app.router.push({ pathname: `${app_config.MainPath}` }); // app.router.push({ pathname: `${app_config.MainPath}` });
@ -123,7 +127,7 @@ export default {
*login({ payload }, { call, put, select }) { *login({ payload }, { call, put, select }) {
if (!payload) return false; if (!payload) return false;
const { user_id, access_token } = payload.authFrame const { user_id, access_token } = payload.authFrame
return yield put({ type: 'handleLogin', payload: { user_id, access_token, user_data: payload.dataFrame } }) yield put({ type: 'handleLogin', payload: { user_id, access_token, user_data: payload.dataFrame } })
}, },
*guestLogin({ payload }, { put, select }) { *guestLogin({ payload }, { put, select }) {
@ -316,31 +320,19 @@ export default {
} }
} }
}, },
appControl(state, {payload}){ appControl(state, {payload}){
if (!payload) return false if (!payload) return false
const ipc = state.electron.ipcRenderer const ipc = state.electron.ipcRenderer
ipc.invoke(payload) ipc.invoke(payload)
// Specials behaviors
// switch (payload) {
// case "hide-window":{
// return ipc.invoke('hide-window')
// }
// case "close":{
// return ipc.invoke('close-window')
// }
// case "quit":{
// return ipc.invoke('quit-app')
// }
// case "minimize-window":{
// return ipc.invoke('minimize-window')
// }
// default:
// break;
// }
}, },
ipcInvoke(state, {payload}){
if (!payload || !state.embedded) {
return false
}
console.log('INVOKING => ', payload)
const ipc = state.electron.ipcRenderer
ipc.invoke(payload.key, payload.payload)
},
allNotificationsRead(state) { allNotificationsRead(state) {
state.notifications = []; state.notifications = [];
}, },

View File

@ -1,9 +1,74 @@
import React from 'react' import React from 'react'
import { PostCreator } from 'components' import { List } from 'antd'
export default class Explore_Page extends React.Component{ import endpoints from 'config/endpoints'
render(){ import { v3_model } from 'core/libs'
return( import { connect } from 'umi'
<PostCreator /> import settings from 'core/libs/settings'
import { PostCard, PostCreator } from 'components'
import * as antd from 'antd'
@connect(({ app }) => ({ app }))
export default class Explore extends React.Component {
state = {
feed: null
}
request(){
v3_model.api_request(
{
body: {limit: settings("post_catchlimit"), type: "get_news_feed"},
serverKey: this.props.app.server_key,
userToken: this.props.app.session_token,
endpoint: endpoints.posts,
verbose: true,
},
(err, res) => {
try {
this.setState({ feed: JSON.parse(res)['data'] })
} catch (error) {
// terrible (⓿_⓿)
}
}
) )
} }
componentDidMount(){
if (this.props.app.session_valid) {
this.request()
}
window.addEventListener('contextmenu', (e) => {
this.props.dispatch({
type: "app/ipcInvoke",
payload: { key: "contextualMenu", payload: {x: e.clientX, y: e.clientY} }
})
},false)
}
render() {
if (!this.state.feed){
return (
<antd.Card bordered="false" >
<antd.Skeleton active />
</antd.Card>
)
}
return(
<>
<PostCreator />
<List
//loadMore={loadMore}
dataSource={this.state.feed}
renderItem={item => (
<div id={item.id}>
<PostCard payload={item} key={item.id} />
</div>
)}
/>
</>
)
}
} }

View File

@ -1,13 +0,0 @@
import React from 'react';
import { PostCreator, MainFeed } from 'components';
export default class Main extends React.Component {
render() {
return (
<>
<PostCreator />
<MainFeed auto={true} get="feed" />
</>
);
}
}

View File

@ -11,6 +11,7 @@
@import './layout/Primary_Layout.less'; @import './layout/Primary_Layout.less';
@import './layout/LeftSider.less'; @import './layout/LeftSider.less';
@import './components/PostCard.less';
::-webkit-scrollbar { ::-webkit-scrollbar {
position: absolute; position: absolute;

View File

@ -13,7 +13,7 @@
@__Global_texted_font: "Manrope", sans-serif; @__Global_texted_font: "Manrope", sans-serif;
@__Global_alternative_font: "Netflix Sans", sans-serif; @__Global_alternative_font: "Netflix Sans", sans-serif;
@__Global_layout_backgroud: #F8F6F8; @__Global_layout_backgroud: #F9F9F9;
@__Global_layout_color: #2d2d2d; @__Global_layout_color: #2d2d2d;
@__Global_layout_border-rd: 27px 0 0 0; @__Global_layout_border-rd: 27px 0 0 0;
@__Global_layout_transitions-dur: 200ms; @__Global_layout_transitions-dur: 200ms;