-
+
+
+
+
+ {
+ processString(messageRegexs)(this.state.data.message ?? "")
+ }
+
+
{
- processString(messageRegexs)(this.state.data.message ?? "")
+ !this.props.disableAttachments && this.state.data.attachments && this.state.data.attachments.length > 0 &&
}
+
+
{
- !this.props.disableAttachments && this.state.data.attachments && this.state.data.attachments.length > 0 &&
+ !this.props.disableHasReplies && !!this.state.hasReplies &&
app.navigation.goToPost(this.state.data._id)}
+ >
+ View {this.state.hasReplies} replies
+
}
-
-
- {
- !this.props.disableHasReplies && !!this.state.hasReplies &&
app.navigation.goToPost(this.state.data._id)}
- >
- View {this.state.hasReplies} replies
-
- }
-
+
}
}
\ No newline at end of file
diff --git a/packages/app/src/components/PostCard/index.less b/packages/app/src/components/PostCard/index.less
index cc178712..5ec61855 100755
--- a/packages/app/src/components/PostCard/index.less
+++ b/packages/app/src/components/PostCard/index.less
@@ -33,6 +33,13 @@
color: var(--text-color);
}
+ .post_card_content {
+ display: flex;
+ flex-direction: column;
+
+ gap: 15px;
+ }
+
.post_content {
position: relative;
diff --git a/packages/app/src/components/RenderWindow/index.jsx b/packages/app/src/components/RenderWindow/index.jsx
deleted file mode 100755
index d990bc70..00000000
--- a/packages/app/src/components/RenderWindow/index.jsx
+++ /dev/null
@@ -1,233 +0,0 @@
-import React from "react"
-import ReactDOM from "react-dom"
-import { Rnd } from "react-rnd"
-import { Icons } from "@components/Icons"
-
-import "./index.less"
-
-class DOMWindow {
- constructor(props = {}) {
- this.props = props
-
- this.id = this.props.id
- this.key = 0
-
- this.currentRender = null
- this.root = document.getElementById("app_windows")
- this.element = document.createElement("div")
-
- this.element.setAttribute("id", this.id)
- this.element.setAttribute("key", this.key)
- this.element.setAttribute("classname", this.props.className)
-
- // if props clickOutsideToClose is true, add event listener to close window
- if (this.props.clickOutsideToClose) {
- document.addEventListener("click", this.handleWrapperClick)
- }
-
- // handle root container
- if (!this.root) {
- this.root = document.createElement("div")
- this.root.setAttribute("id", "app_windows")
-
- document.body.append(this.root)
- }
-
- // get all windows opened has container
- const rootNodes = this.root.childNodes
-
- // ensure this window has last key from rootNode
- if (rootNodes.length > 0) {
- const lastChild = rootNodes[rootNodes.length - 1]
- const lastChildKey = Number(lastChild.getAttribute("key"))
-
- this.key = lastChildKey + 1
- }
- }
-
- handleWrapperClick = (event) => {
- if (!this.currentRender) {
- return
- }
-
- // if click in not renderer fragment, close window
- if (!this.element.contains(event.target)) {
- this.remove()
- }
- }
-
- render = (fragment) => {
- this.root.appendChild(this.element)
-
- this.currentRender = fragment
-
- return ReactDOM.render(fragment, this.element)
- }
-
- remove = () => {
- this.root.removeChild(this.element)
- this.currentRender = null
- }
-
- destroy = () => {
- this.element.remove()
- this.currentRender = null
- }
-
- createDefaultWindow = (children, props) => {
- return this.render(
- {children}
- )
- }
-}
-
-class DefaultWindowRender extends React.Component {
- state = {
- actions: [],
- dimensions: {
- height: this.props.height ?? 600,
- width: this.props.width ?? 400,
- },
- position: this.props.defaultPosition,
- visible: false,
- }
-
- componentDidMount = () => {
- this.setDefaultActions()
-
- if (typeof this.props.actions !== "undefined") {
- if (Array.isArray(this.props.actions)) {
- const actions = this.state.actions ?? []
-
- this.props.actions.forEach((action) => {
- actions.push(action)
- })
-
- this.setState({ actions })
- }
- }
-
- if (!this.state.position) {
- this.setState({ position: this.getCenterPosition() })
- }
-
- this.toggleVisibility(true)
- }
-
- toggleVisibility = (to) => {
- this.setState({ visible: to ?? !this.state.visible })
- }
-
- getCenterPosition = () => {
- const dimensions = this.state?.dimensions ?? {}
-
- const windowHeight = dimensions.height ?? 600
- const windowWidth = dimensions.width ?? 400
-
- return {
- x: window.innerWidth / 2 - windowWidth / 2,
- y: window.innerHeight / 2 - windowHeight / 2,
- }
- }
-
- setDefaultActions = () => {
- const { actions } = this.state
-
- actions.push({
- key: "close",
- render: () =>
,
- onClick: () => {
- this.props.destroy()
- },
- })
-
- this.setState({ actions })
- }
-
- renderActions = () => {
- const actions = this.state.actions
-
- if (Array.isArray(actions)) {
- return actions.map((action) => {
- return (
-
- {React.isValidElement(action.render) ? action.render : React.createElement(action.render)}
-
- )
- })
- }
-
- return null
- }
-
- getComponentRender = () => {
- return React.isValidElement(this.props.children)
- ? React.cloneElement(this.props.children, this.props.renderProps)
- : React.createElement(this.props.children, this.props.renderProps)
- }
-
- render() {
- const { position, dimensions, visible } = this.state
-
- if (!visible) {
- return null
- }
-
- return (
-
{
- this.setState({
- dimensions: {
- width: ref.offsetWidth,
- height: ref.offsetHeight,
- },
- position,
- })
- }}
- minWidth={
- this.props.minWidth
- }
- minHeight={
- this.props.minHeight
- }
- enableResizing={
- this.props.enableResizing ?? true
- }
- disableDragging={
- this.props.disableDragging ?? false
- }
- dragHandleClassName={
- this.props.dragHandleClassName ?? "window_topbar"
- }
- bounds={
- this.props.bounds ?? "#root"
- }
- >
- {
- this.props.useWrapper
- ?
-
-
{this.props.id}
-
{this.renderActions()}
-
-
-
{this.getComponentRender()}
-
- : this.props.children
- }
-
- )
- }
-}
-
-export { DOMWindow, DefaultWindowRender }
\ No newline at end of file
diff --git a/packages/app/src/components/RenderWindow/index.less b/packages/app/src/components/RenderWindow/index.less
deleted file mode 100755
index 921e0306..00000000
--- a/packages/app/src/components/RenderWindow/index.less
+++ /dev/null
@@ -1,93 +0,0 @@
-@wrapper_background: rgba(255, 255, 255, 1);
-
-@topbar_height: 30px;
-@topbar_background: rgba(0, 0, 0, 0.4);
-
-.window_wrapper {
- border-radius: 12px;
-
- background-color: @wrapper_background;
- border: 1px solid rgba(161, 133, 133, 0.2);
- overflow: hidden;
-
- &.translucid {
- border: unset;
- background-color: rgba(0, 0, 0, 0.2);
-
- backdrop-filter: blur(10px);
- --webkit-backdrop-filter: blur(10px);
- filter: drop-shadow(8px 8px 10px rgba(0, 0, 0, 0.5));
- }
-}
-
-.window_topbar {
- position: sticky;
- z-index: 51;
- background-color: @topbar_background;
-
- height: @topbar_height;
- width: 100%;
-
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: space-between;
-
- > div {
- margin: 0 5px;
- line-height: 0;
- }
-
- .title {
- margin-left: 20px;
-
- color: #fff - @topbar_background;
-
- font-size: 13px;
- font-style: italic;
- font-family: "JetBrains Mono", monospace;
- }
-
- .actions {
- display: flex;
- flex-direction: row-reverse;
- align-items: center;
- justify-content: end;
-
- color: #fff - @topbar_background;
-
- > div {
- transition: all 150ms ease-in-out;
- margin-right: 10px;
- cursor: pointer;
-
- height: fit-content;
- width: fit-content;
- line-height: 0;
-
- display: flex;
- align-items: center;
- justify-content: end;
- }
- > div:hover {
- color: var(--primary-color);
- }
- }
-}
-
-.window_body {
- z-index: 50;
-
- padding: 10px 20px;
- height: calc(100% - @topbar_height);
- width: 100%;
-
- overflow: overlay;
- user-select: text !important;
- --webkit-user-select: text !important;
-
- > div {
- user-select: text !important;
- --webkit-user-select: text !important;
- }
-}
diff --git a/packages/app/src/components/WidgetsBrowser/index.jsx b/packages/app/src/components/WidgetsBrowser/index.jsx
index 1a987f4a..2d74ed9e 100755
--- a/packages/app/src/components/WidgetsBrowser/index.jsx
+++ b/packages/app/src/components/WidgetsBrowser/index.jsx
@@ -5,12 +5,11 @@ import { Icons } from "@components/Icons"
import WidgetItemPreview from "@components/WidgetItemPreview"
import useRequest from "comty.js/hooks/useRequest"
-import WidgetModel from "comty.js/models/widget"
import "./index.less"
export const WidgetBrowser = (props) => {
- const [L_Widgets, R_Widgets, E_Widgets, M_Widgets] = useRequest(WidgetModel.browse)
+ const [L_Widgets, R_Widgets, E_Widgets, M_Widgets] = []
const [searchValue, setSearchValue] = React.useState("")
diff --git a/packages/app/src/components/index.js b/packages/app/src/components/index.js
index 35b86883..4502f3b8 100755
--- a/packages/app/src/components/index.js
+++ b/packages/app/src/components/index.js
@@ -1,4 +1,3 @@
-import * as Layout from "./Layout"
export { default as Footer } from "./Footer"
export { default as RenderError } from "./RenderError"
@@ -40,9 +39,4 @@ export { default as PostCreator } from "./PostCreator"
export { default as UserBadges } from "./UserBadges"
export { default as UserCard } from "./UserCard"
export { default as FollowersList } from "./FollowersList"
-export { default as UserPreview } from "./UserPreview"
-
-// OTHERS
-export * as Window from "./RenderWindow"
-
-export { Layout }
\ No newline at end of file
+export { default as UserPreview } from "./UserPreview"
\ No newline at end of file
diff --git a/packages/app/src/cores/contextMenu/components/contextMenu/index.less b/packages/app/src/cores/contextMenu/components/contextMenu/index.less
index 19ff4dfe..3900466f 100755
--- a/packages/app/src/cores/contextMenu/components/contextMenu/index.less
+++ b/packages/app/src/cores/contextMenu/components/contextMenu/index.less
@@ -1,5 +1,5 @@
.contextMenu {
- position: absolute;
+ position: fixed;
z-index: 100000;
display: flex;
@@ -8,7 +8,7 @@
top: 0;
left: 0;
- width: 200px;
+ width: 230px;
height: fit-content;
background-color: var(--background-color-primary);
@@ -16,11 +16,11 @@
border-radius: 8px;
- padding: 10px;
+ padding: 7px;
- font-family: "Recursive", sans-serif;
+ font-weight: 600;
+ font-family: var(--fontFamily);
font-size: 0.8rem;
- font-weight: 500;
color: var(--text-color);
h1,
@@ -42,7 +42,7 @@
align-items: center;
justify-content: space-between;
- padding: 10px 10px 10px 20px;
+ padding: 10px 10px 10px 15px;
transition: all 50ms ease-in-out;
@@ -52,7 +52,7 @@
&:hover {
background-color: var(--background-color-accent);
- padding-left: 25px;
+ padding-left: 18px;
}
&:active {
diff --git a/packages/app/src/cores/contextMenu/context_menu.core.js b/packages/app/src/cores/contextMenu/context_menu.core.js
index 407d9def..f618a295 100755
--- a/packages/app/src/cores/contextMenu/context_menu.core.js
+++ b/packages/app/src/cores/contextMenu/context_menu.core.js
@@ -1,10 +1,10 @@
import React from "react"
import Core from "evite/src/core"
-import { DOMWindow } from "@components/RenderWindow"
import ContextMenu from "./components/contextMenu"
-import InternalContexts from "@config/context-menu"
+import DefaultContenxt from "@config/context-menu/default"
+import PostCardContext from "@config/context-menu/post"
export default class ContextMenuCore extends Core {
static namespace = "contextMenu"
@@ -15,13 +15,10 @@ export default class ContextMenuCore extends Core {
registerContext: this.registerContext.bind(this),
}
- contexts = Object()
-
- DOMWindow = new DOMWindow({
- id: "contextMenu",
- className: "contextMenuWrapper",
- clickOutsideToClose: true,
- })
+ contexts = {
+ ...DefaultContenxt,
+ ...PostCardContext,
+ }
async onInitialize() {
if (app.isMobile) {
@@ -65,27 +62,26 @@ export default class ContextMenuCore extends Core {
contexts.push("default-context")
}
- for await (const context of contexts) {
- let contextObject = this.contexts[context] || InternalContexts[context]
+ for await (const [index, context] of contexts.entries()) {
+ let contextObject = this.contexts[context]
+
+ if (!contextObject) {
+ this.console.warn(`Context ${context} not found`)
+ continue
+ }
if (typeof contextObject === "function") {
- contextObject = await contextObject(parentElement, element, {
+ contextObject = await contextObject(items, parentElement, element, {
close: this.hide,
})
}
// push divider
- if (items.length > 0) {
+ if (contexts.length > 0 && index !== contexts.length - 1) {
items.push({
type: "separator"
})
}
-
- if (Array.isArray(contextObject)) {
- items.push(...contextObject)
- } else {
- items.push(contextObject)
- }
}
// fullfill each item with a correspondent index if missing declared
@@ -142,10 +138,13 @@ export default class ContextMenuCore extends Core {
}
show(payload) {
- this.DOMWindow.render(React.createElement(ContextMenu, payload))
+ app.cores.window_mng.render("context-menu", React.createElement(ContextMenu, payload), {
+ createOrUpdate: true,
+ closeOnClickOutside: true,
+ })
}
hide() {
- this.DOMWindow.remove()
+ app.cores.window_mng.close("context-menu")
}
}
\ No newline at end of file
diff --git a/packages/app/src/cores/notifications/feedback.js b/packages/app/src/cores/notifications/feedback.js
index 9095f064..aaab127b 100644
--- a/packages/app/src/cores/notifications/feedback.js
+++ b/packages/app/src/cores/notifications/feedback.js
@@ -12,7 +12,7 @@ class NotificationFeedback {
return (window.app.cores.settings.get("sfx:notifications_volume") ?? 50) / 100
}
- static playHaptic = async (options = {}) => {
+ static playHaptic = async () => {
if (app.cores.settings.get("haptics:notifications_feedback")) {
await Haptics.vibrate()
}
@@ -28,7 +28,11 @@ class NotificationFeedback {
}
}
- static async feedback(type) {
+ static async feedback({ type = "notification", feedback = true }) {
+ if (!feedback) {
+ return false
+ }
+
NotificationFeedback.playHaptic(type)
NotificationFeedback.playAudio(type)
}
diff --git a/packages/app/src/cores/notifications/notifications.core.js b/packages/app/src/cores/notifications/notifications.core.js
index 314afff5..2776e29d 100755
--- a/packages/app/src/cores/notifications/notifications.core.js
+++ b/packages/app/src/cores/notifications/notifications.core.js
@@ -22,10 +22,15 @@ export default class NotificationCore extends Core {
public = {
new: this.new,
+ close: this.close,
}
- async new(notification, options = {}) {
- NotificationUI.notify(notification, options)
- NotificationFeedback.feedback(options.type)
+ async new(notification) {
+ NotificationUI.notify(notification)
+ NotificationFeedback.feedback(notification)
+ }
+
+ async close(id) {
+ NotificationUI.close(id)
}
}
\ No newline at end of file
diff --git a/packages/app/src/cores/notifications/ui.jsx b/packages/app/src/cores/notifications/ui.jsx
index 770f4a71..a7c296e9 100644
--- a/packages/app/src/cores/notifications/ui.jsx
+++ b/packages/app/src/cores/notifications/ui.jsx
@@ -5,12 +5,7 @@ import { notification as Notf, Space, Button } from "antd"
import { Icons, createIconRender } from "@components/Icons"
class NotificationUI {
- static async notify(
- notification,
- options = {
- type: "info"
- }
- ) {
+ static async notify(notification) {
if (typeof notification === "string") {
notification = {
title: "New notification",
@@ -19,8 +14,8 @@ class NotificationUI {
}
const notfObj = {
- duration: options.duration ?? 4,
- key: options.key ?? Date.now(),
+ duration: typeof notification.duration === "undefined" ? 4 : notification.duration,
+ key: notification.key ?? Date.now(),
}
if (notification.title) {
@@ -73,11 +68,11 @@ class NotificationUI {
notfObj.icon = React.isValidElement(notification.icon) ? notification.icon : (createIconRender(notification.icon) ??
)
}
- if (Array.isArray(options.actions)) {
+ if (Array.isArray(notification.actions)) {
notfObj.btn = (
{
- options.actions.map((action, index) => {
+ notification.actions.map((action, index) => {
const handleClick = () => {
if (typeof action.onClick === "function") {
action.onClick()
@@ -101,11 +96,24 @@ class NotificationUI {
)
}
- if (typeof Notf[options.type] !== "function") {
- options.type = "info"
+ if (typeof notification.closable) {
+ notfObj.closable = notification.closable
}
- return Notf[options.type](notfObj)
+ if (notification.type === "loading") {
+ notification.type = "open"
+ notfObj.icon =
+ }
+
+ if (typeof Notf[notification.type] !== "function") {
+ notification.type = "info"
+ }
+
+ return Notf[notification.type](notfObj)
+ }
+
+ static close(key) {
+ Notf.destroy(key)
}
}
diff --git a/packages/app/src/cores/player/player.core.js b/packages/app/src/cores/player/player.core.js
index 177b0572..9eeb8115 100755
--- a/packages/app/src/cores/player/player.core.js
+++ b/packages/app/src/cores/player/player.core.js
@@ -110,7 +110,8 @@ export default class Player extends Core {
set: (target, prop, value) => {
return false
}
- })
+ }),
+ gradualFadeMs: Player.gradualFadeMs,
}
internalEvents = {
@@ -128,10 +129,6 @@ export default class Player extends Core {
},
}
- wsEvents = {
-
- }
-
async onInitialize() {
this.native_controls.initialize()
@@ -695,6 +692,10 @@ export default class Player extends Core {
}
async resumePlayback() {
+ if (!this.state.playback_status === "playing") {
+ return true
+ }
+
return await new Promise((resolve, reject) => {
if (!this.track_instance) {
this.console.error("No audio instance")
diff --git a/packages/app/src/cores/remoteStorage/remoteStorage.core.js b/packages/app/src/cores/remoteStorage/remoteStorage.core.js
index f3f71bae..62810b5b 100755
--- a/packages/app/src/cores/remoteStorage/remoteStorage.core.js
+++ b/packages/app/src/cores/remoteStorage/remoteStorage.core.js
@@ -32,8 +32,7 @@ export default class RemoteStorage extends Core {
const fn = async () => new Promise((resolve, reject) => {
const uploader = new ChunkedUpload({
endpoint: `${app.cores.api.client().mainOrigin}/upload/chunk`,
- // TODO: get chunk size from settings
- splitChunkSize: 5 * 1024 * 1024, // 5MB in bytes
+ splitChunkSize: 5 * 1024 * 1024,
file: file,
service: service,
})
diff --git a/packages/app/src/cores/style/style.core.jsx b/packages/app/src/cores/style/style.core.jsx
index 151b9669..12096da6 100755
--- a/packages/app/src/cores/style/style.core.jsx
+++ b/packages/app/src/cores/style/style.core.jsx
@@ -239,8 +239,6 @@ export default class StyleCore extends Core {
app.eventBus.emit("style.update", {
...this.public.mutation,
})
-
- ConfigProvider.config({ theme: this.public.mutation })
}
applyVariant(variant = (this.public.theme.defaultVariant ?? "light")) {
diff --git a/packages/app/src/cores/windows/components/defaultWindow/context.js b/packages/app/src/cores/windows/components/defaultWindow/context.js
new file mode 100644
index 00000000..084160fb
--- /dev/null
+++ b/packages/app/src/cores/windows/components/defaultWindow/context.js
@@ -0,0 +1,17 @@
+import React from "react"
+
+export default React.createContext({
+ title: null,
+ close: () => { },
+ updatePosition: () => { },
+ updateDimensions: () => { },
+ updateTitle: () => { },
+ position: {
+ x: 0,
+ y: 0,
+ },
+ dimensions: {
+ width: 0,
+ height: 0,
+ },
+})
\ No newline at end of file
diff --git a/packages/app/src/cores/windows/components/defaultWindow/index.jsx b/packages/app/src/cores/windows/components/defaultWindow/index.jsx
new file mode 100644
index 00000000..44e4b238
--- /dev/null
+++ b/packages/app/src/cores/windows/components/defaultWindow/index.jsx
@@ -0,0 +1,196 @@
+import React from "react"
+import { Rnd } from "react-rnd"
+
+import { Icons } from "@components/Icons"
+
+import WindowContext from "./context"
+
+export default class DefaultWindowRender extends React.Component {
+ static contextType = WindowContext
+
+ ref = React.createRef()
+
+ state = {
+ renderError: false,
+ title: null,
+ actions: [],
+ dimensions: {
+ height: this.props.height ?? 600,
+ width: this.props.width ?? 400,
+ },
+ position: this.props.defaultPosition,
+ visible: false,
+ }
+
+ componentDidMount = () => {
+ this.setDefaultActions()
+
+ if (typeof this.props.actions !== "undefined") {
+ if (Array.isArray(this.props.actions)) {
+ const actions = this.state.actions ?? []
+
+ this.props.actions.forEach((action) => {
+ actions.push(action)
+ })
+
+ this.setState({ actions })
+ }
+ }
+
+ if (!this.state.position) {
+ this.setState({ position: this.getCenterPosition() })
+ }
+
+ this.toggleVisibility(true)
+ }
+
+ componentDidCatch = (error) => {
+ console.error(error)
+
+ this.setState({
+ renderError: error,
+ })
+ }
+
+ updateTitle = (title) => {
+ this.setState({ title })
+ }
+
+ updateDimensions = (dimensions = {
+ width: 0,
+ height: 0,
+ }) => {
+ this.ref.current?.updateSize({
+ width: dimensions.width,
+ height: dimensions.height,
+ })
+ }
+
+ updatePosition = (position = {
+ x: 0,
+ y: 0,
+ }) => {
+ this.ref.current?.updatePosition({
+ x: position.x,
+ y: position.y,
+ })
+ }
+
+ toggleVisibility = (to) => {
+ this.setState({ visible: to ?? !this.state.visible })
+ }
+
+ getCenterPosition = () => {
+ const dimensions = this.state?.dimensions ?? {}
+
+ const windowHeight = dimensions.height ?? 600
+ const windowWidth = dimensions.width ?? 400
+
+ return {
+ x: window.innerWidth / 2 - windowWidth / 2,
+ y: window.innerHeight / 2 - windowHeight / 2,
+ }
+ }
+
+ setDefaultActions = () => {
+ const { actions } = this.state
+
+ actions.push({
+ key: "close",
+ render: () => ,
+ onClick: () => {
+ this.props.close()
+ },
+ })
+
+ this.setState({ actions })
+ }
+
+ renderActions = () => {
+ const actions = this.state.actions
+
+ if (Array.isArray(actions)) {
+ return actions.map((action) => {
+ return (
+
+ {React.isValidElement(action.render) ? action.render : React.createElement(action.render)}
+
+ )
+ })
+ }
+
+ return null
+ }
+
+ getComponentRender = () => {
+ const ctx = {
+ ...this.props,
+ updateTitle: this.updateTitle,
+ updateDimensions: this.updateDimensions,
+ updatePosition: this.updatePosition,
+ close: this.props.close,
+ position: this.state.position,
+ dimensions: this.state.dimensions,
+ }
+
+ return
+ {
+ React.isValidElement(this.props.children)
+ ? React.cloneElement(this.props.children, ctx)
+ : React.createElement(this.props.children, ctx)
+ }
+
+ }
+
+ render() {
+ const { position, dimensions, visible } = this.state
+
+ if (!visible) {
+ return null
+ }
+
+ return
+
+
{this.state.title}
+
{this.renderActions()}
+
+
+
+ {
+ this.state.renderError &&
+
Render Error
+ {this.state.renderError.message}
+
+ }
+ {
+ !this.state.renderError && this.getComponentRender()
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/packages/app/src/cores/windows/index.less b/packages/app/src/cores/windows/index.less
new file mode 100644
index 00000000..83cd8a9c
--- /dev/null
+++ b/packages/app/src/cores/windows/index.less
@@ -0,0 +1,115 @@
+@topbar_height: 30px;
+@topbar_background: var(--background-color-accent);
+
+.window_wrapper {
+ border-radius: 12px;
+
+ background-color: var(--background-color-primary);
+ border: 2px solid var(--border-color);
+
+ //filter: drop-shadow(0 0 10px rgba(0, 0, 0, 0.5));
+
+ overflow: hidden;
+}
+
+.window_topbar {
+ position: sticky;
+
+ z-index: 51;
+
+ background-color: @topbar_background;
+
+ color: var(--text-color);
+
+ height: @topbar_height;
+ width: 100%;
+
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+
+ >div {
+ margin: 0 5px;
+ line-height: 0;
+ }
+
+ .title {
+ margin-left: 20px;
+
+ color: var(--text-color);
+
+ font-size: 13px;
+ font-style: italic;
+ font-family: "JetBrains Mono", monospace;
+ }
+
+ .actions {
+ display: flex;
+ flex-direction: row-reverse;
+ align-items: center;
+ justify-content: end;
+
+ color: var(--text-color);
+
+ >div {
+ transition: all 150ms ease-in-out;
+ margin-right: 10px;
+ cursor: pointer;
+
+ height: fit-content;
+ width: fit-content;
+ line-height: 0;
+
+ display: flex;
+ align-items: center;
+ justify-content: end;
+ }
+
+ >div:hover {
+ color: var(--primary-color);
+ }
+ }
+}
+
+.window_body {
+ z-index: 50;
+
+ padding: 10px 20px;
+ height: calc(100% - @topbar_height);
+ width: 100%;
+
+ overflow: overlay;
+ user-select: text !important;
+ --webkit-user-select: text !important;
+
+ color: var(--text-color);
+
+ >div {
+ user-select: text !important;
+ --webkit-user-select: text !important;
+ }
+
+ .render_error {
+ display: flex;
+ flex-direction: column;
+
+ align-items: center;
+
+ width: 100%;
+ height: 100%;
+
+ h1 {
+ font-size: 2rem;
+ }
+
+ code {
+ background-color: var(--background-color-accent);
+
+ padding: 5px;
+ border-radius: 8px;
+
+ user-select: text;
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/app/src/cores/windows/windows.core.jsx b/packages/app/src/cores/windows/windows.core.jsx
new file mode 100644
index 00000000..0ebe4dda
--- /dev/null
+++ b/packages/app/src/cores/windows/windows.core.jsx
@@ -0,0 +1,151 @@
+import React from "react"
+import Core from "evite/src/core"
+
+import { createRoot } from "react-dom/client"
+
+import DefaultWindow from "./components/defaultWindow"
+
+import DefaultWindowContext from "./components/defaultWindow/context"
+
+import "./index.less"
+
+export default class WindowManager extends Core {
+ static namespace = "window_mng"
+
+ static idMount = "windows"
+
+ root = null
+
+ windows = []
+
+ public = {
+ close: this.close.bind(this),
+ render: this.render.bind(this),
+ }
+
+ async onInitialize() {
+ this.root = document.createElement("div")
+
+ this.root.setAttribute("id", this.constructor.idMount)
+
+ document.body.append(this.root)
+ }
+
+ handleWrapperClick = (id, event) => {
+ const element = this.root.querySelector(`#${id}`)
+
+ if (element) {
+ if (!element.contains(event.target)) {
+ this.close(id)
+ }
+ }
+ }
+
+ /**
+ * Creates a new element with the specified id and appends it to the root element.
+ * If the element already exists and createOrUpdate option is false, it will throw an error.
+ * If the element already exists and createOrUpdate option is true, it will update the element.
+ * If useFrame option is true, it wraps the fragment with a DefaultWindow component before rendering.
+ *
+ * @param {string} id - The id of the element to create or update.
+ * @param {ReactElement} fragment - The React element to render inside the created element.
+ * @param {Object} options - The options for creating or updating the element.
+ * @param {boolean} options.useFrame - Specifies whether to wrap the fragment with a DefaultWindow component.
+ * @param {boolean} options.createOrUpdate - Specifies whether to create a new element or update an existing one.
+ * @return {HTMLElement} The created or updated element.
+ */
+ render(
+ id,
+ fragment,
+ {
+ useFrame = false,
+ createOrUpdate = false,
+ closeOnClickOutside = false,
+ } = {}
+ ) {
+ let element = document.createElement("div")
+ let node = null
+ let win = null
+
+ // check if window already exist
+ if (this.root.querySelector(`#${id}`) && !createOrUpdate) {
+ const newId = `${id}_${Date.now()}`
+
+ this.console.warn(`Window ${id} already exist, overwritting id to ${newId}.\nYou can use {createOrUpdate = true} option to force refresh render of window`)
+
+ id = newId
+ }
+
+ if (this.root.querySelector(`#${id}`) && createOrUpdate) {
+ element = document.getElementById(id)
+
+ win = this.windows.find((_node) => {
+ return _node.id === id
+ })
+
+ if (win) {
+ node = win.node
+ }
+ } else {
+ element.setAttribute("id", id)
+
+ this.root.appendChild(element)
+
+ node = createRoot(element)
+
+ win = {
+ id: id,
+ node: node,
+ }
+
+ this.windows.push(win)
+ }
+
+ if (useFrame) {
+ fragment =
+ {fragment}
+
+ }
+
+ if (closeOnClickOutside) {
+ document.addEventListener("click", (e) => this.handleWrapperClick(id, e))
+ }
+
+ node.render(React.cloneElement(fragment, {
+ close: () => {
+ this.close(id)
+ }
+ }))
+
+ return element
+ }
+
+ /**
+ * Closes the window with the given ID.
+ *
+ * @param {string} id - The ID of the window to be closed.
+ * @return {boolean} Returns true if the window was successfully closed, false otherwise.
+ */
+ close(id) {
+ const element = document.getElementById(id)
+
+ const win = this.windows.find((node) => {
+ return node.id === id
+ })
+
+ if (!win) {
+ this.console.warn(`Window ${id} not found`)
+
+ return false
+ }
+
+ win.node.unmount()
+ this.root.removeChild(element)
+
+ this.windows = this.windows.filter((node) => {
+ return node.id !== id
+ })
+
+ return true
+ }
+}
\ No newline at end of file
diff --git a/packages/app/src/hooks/useChat/index.js b/packages/app/src/hooks/useChat/index.js
new file mode 100644
index 00000000..a19d4139
--- /dev/null
+++ b/packages/app/src/hooks/useChat/index.js
@@ -0,0 +1,98 @@
+import React from "react"
+
+export default (to_user_id) => {
+ const [socket, setSocket] = React.useState(null)
+ const [messages, setMessages] = React.useState([])
+ const [scroller, setScroller] = React.useState(null)
+
+ const [isLocalTyping, setIsLocalTyping] = React.useState(false)
+ const [isRemoteTyping, setIsRemoteTyping] = React.useState(false)
+
+ const [timeoutOffTypingEvent, setTimeoutOffTypingEvent] = React.useState(null)
+
+ async function sendMessage(message) {
+ emitTypingEvent(false)
+
+ await socket.emit("chat:send:message", {
+ to_user_id: to_user_id,
+ content: message,
+ })
+ }
+
+ async function emitTypingEvent(to) {
+ if (isLocalTyping === true && to === true) {
+ return debouncedOffTypingEvent()
+ }
+
+ await socket.emit("chat:state:typing", {
+ to_user_id: to_user_id,
+ is_typing: to,
+ })
+
+ setIsLocalTyping(to)
+ }
+
+ async function debouncedOffTypingEvent() {
+ if (timeoutOffTypingEvent) {
+ clearTimeout(timeoutOffTypingEvent)
+ }
+
+ setTimeoutOffTypingEvent(setTimeout(() => {
+ emitTypingEvent(false)
+ }, 5000))
+ }
+
+ const listenEvents = {
+ "chat:receive:message": (message) => {
+ setMessages((messages) => {
+ return [
+ ...messages,
+ message
+ ]
+ })
+ },
+ "chat:state:typing": (state) => {
+ setIsRemoteTyping(state.is_typing)
+ },
+ }
+
+ React.useEffect(() => {
+ if (scroller?.current) {
+ const paddingBottom = scroller.current.style.paddingBottom.replace("px", "")
+
+ scroller.current?.scrollTo({
+ top: scroller.current.scrollHeight + paddingBottom,
+ behavior: "smooth",
+ })
+ }
+ }, [messages])
+
+ React.useEffect(() => {
+ const targetSocket = app.cores.api.client().sockets.chats
+
+ setSocket(targetSocket)
+
+ for (const [event, handler] of Object.entries(listenEvents)) {
+ targetSocket.on(event, handler)
+ }
+
+ return () => {
+ for (const [event, handler] of Object.entries(listenEvents)) {
+ targetSocket.off(event, handler)
+ }
+
+ if (timeoutOffTypingEvent) {
+ clearTimeout(timeoutOffTypingEvent)
+ }
+ }
+ }, [])
+
+ return {
+ sendMessage,
+ messages,
+ setMessages,
+ setScroller,
+ emitTypingEvent,
+ isRemoteTyping,
+ }
+}
\ No newline at end of file
diff --git a/packages/app/src/hooks/useTextRoom/index.jsx b/packages/app/src/hooks/useTextRoom/index.jsx
new file mode 100644
index 00000000..7008bff6
--- /dev/null
+++ b/packages/app/src/hooks/useTextRoom/index.jsx
@@ -0,0 +1,70 @@
+import React from "react"
+import { EventEmitter } from "@foxify/events"
+
+function useTextRoom(route, options = {
+ persistent: false,
+}) {
+ const eventEmitter = new EventEmitter()
+
+ const [lines, setLines] = React.useState([])
+
+ const socket = app.cores.api.client().sockets.chats
+
+ function pushToLines(line) {
+ setLines((lines) => {
+ return [
+ ...lines,
+ line,
+ ]
+ })
+ }
+
+ function deleteLine(message) {
+ setLines((lines) => {
+ return lines.filter((line) => line._id !== message._id)
+ })
+ }
+
+ function send(payload) {
+ socket.emit("room:send:message", {
+ ...payload,
+ route: route,
+ })
+ }
+
+ const socketEvents = {
+ "room:message": (message) => {
+ eventEmitter.emit("room:message", message)
+ pushToLines(message)
+ },
+ "room:delete:message": (message) => {
+ eventEmitter.emit("room:delete:message", message)
+ deleteLine(message)
+ }
+ }
+
+ React.useEffect(() => {
+ socket.emit("join:room", {
+ ...options,
+ room: route,
+ })
+
+ for (const [event, handler] of Object.entries(socketEvents)) {
+ socket.on(event, handler)
+ }
+
+ return () => {
+ socket.emit("leave:room", {
+ room: route,
+ })
+
+ for (const [event, handler] of Object.entries(socketEvents)) {
+ socket.off(event, handler)
+ }
+ }
+ }, [])
+
+ return [send, lines, setLines, eventEmitter]
+}
+
+export default useTextRoom
\ No newline at end of file
diff --git a/packages/app/src/layout.jsx b/packages/app/src/layout.jsx
index e66e7e1a..665e09df 100755
--- a/packages/app/src/layout.jsx
+++ b/packages/app/src/layout.jsx
@@ -44,14 +44,7 @@ export default class Layout extends React.PureComponent {
}
transitionLayer.classList.remove("fade-opacity-leave")
- },
- "router.navigate": async (path, options) => {
- this.progressBar.start()
-
- await this.makePageTransition(options)
-
- this.progressBar.done()
- },
+ }
}
componentDidMount() {
@@ -82,33 +75,6 @@ export default class Layout extends React.PureComponent {
this.setState({ renderError: { info, stack } })
}
- async makePageTransition(options = {}) {
- if (document.startViewTransition) {
- return document.startViewTransition(async () => {
- await new Promise((resolve) => {
- setTimeout(resolve, options.state?.transitionDelay ?? 250)
- })
- })
- }
-
- const content_layout = document.getElementById("content_layout")
-
- if (!content_layout) {
- console.warn("content_layout not found, no animation will be played")
-
- return false
- }
-
- content_layout.classList.add("fade-transverse-leave")
-
- return await new Promise((resolve) => {
- setTimeout(() => {
- resolve()
- content_layout.classList.remove("fade-transverse-leave")
- }, options.state?.transitionDelay ?? 250)
- })
- }
-
layoutInterface = window.app.layout = {
set: (layout) => {
if (typeof Layouts[layout] !== "function") {
diff --git a/packages/app/src/components/Layout/bottomBar/index.jsx b/packages/app/src/layouts/components/bottomBar/index.jsx
similarity index 99%
rename from packages/app/src/components/Layout/bottomBar/index.jsx
rename to packages/app/src/layouts/components/bottomBar/index.jsx
index 09eed364..eff618e9 100755
--- a/packages/app/src/components/Layout/bottomBar/index.jsx
+++ b/packages/app/src/layouts/components/bottomBar/index.jsx
@@ -8,7 +8,7 @@ import { Icons, createIconRender } from "@components/Icons"
import { WithPlayerContext, Context } from "@contexts/WithPlayerContext"
-import { QuickNavMenuItems, QuickNavMenu } from "@components/Layout/quickNav"
+import { QuickNavMenuItems, QuickNavMenu } from "@layouts/components/quickNav"
import PlayerView from "@pages/@mobile-views/player"
import CreatorView from "@pages/@mobile-views/creator"
diff --git a/packages/app/src/components/Layout/bottomBar/index.less b/packages/app/src/layouts/components/bottomBar/index.less
similarity index 100%
rename from packages/app/src/components/Layout/bottomBar/index.less
rename to packages/app/src/layouts/components/bottomBar/index.less
diff --git a/packages/app/src/components/Layout/draggableDrawer/index.jsx b/packages/app/src/layouts/components/draggableDrawer/index.jsx
similarity index 100%
rename from packages/app/src/components/Layout/draggableDrawer/index.jsx
rename to packages/app/src/layouts/components/draggableDrawer/index.jsx
diff --git a/packages/app/src/components/Layout/draggableDrawer/index.less b/packages/app/src/layouts/components/draggableDrawer/index.less
similarity index 100%
rename from packages/app/src/components/Layout/draggableDrawer/index.less
rename to packages/app/src/layouts/components/draggableDrawer/index.less
diff --git a/packages/app/src/components/Layout/drawer/index.jsx b/packages/app/src/layouts/components/drawer/index.jsx
similarity index 100%
rename from packages/app/src/components/Layout/drawer/index.jsx
rename to packages/app/src/layouts/components/drawer/index.jsx
diff --git a/packages/app/src/layouts/components/floatingStack/index.jsx b/packages/app/src/layouts/components/floatingStack/index.jsx
deleted file mode 100755
index c2852cbb..00000000
--- a/packages/app/src/layouts/components/floatingStack/index.jsx
+++ /dev/null
@@ -1,132 +0,0 @@
-import React from "react"
-import classnames from "classnames"
-
-import { DOMWindow } from "@components/RenderWindow"
-
-import "./index.less"
-
-class FloatingStackItem extends React.PureComponent {
- state = {
- renderError: null
- }
-
- componentDidCatch(error, info) {
- console.log(error, info)
-
- this.setState({
- renderError: error,
- })
- }
-
- render() {
- if (this.state.renderError) {
- return
-
Render Error
-
- }
-
- return
-
- {this.props.children}
-
-
- }
-}
-
-export default class FloatingStack extends React.Component {
- state = {
- renders: [],
- globalVisibility: true,
- }
-
- public = {
- add: (id, render) => {
- try {
- if (!id) {
- console.error(`FloatingStack: id is required`)
- return false
- }
- if (!render) {
- console.error(`FloatingStack: render is required`)
- return false
- }
-
- if (this.state.renders.find((item) => item.id === id)) {
- console.error(`FloatingStack: id ${id} already exists`)
- return false
- }
-
- this.setState({
- renders: [
- ...this.state.renders,
- {
- id,
- render: React.createElement(render),
- },
- ]
- })
-
- return render
- } catch (error) {
- console.log(error)
- return null
- }
- },
- remove: (id) => {
- this.setState({
- renders: this.state.renders.filter((item) => {
- return item.id !== id
- })
- })
-
- return true
- },
- toggleGlobalVisibility: (to) => {
- if (typeof to !== "boolean") {
- to = !this.state.globalVisibility
- }
-
- this.setState({
- globalVisibility: to,
- })
- }
- }
-
- componentDidMount() {
- window.app.layout.floatingStack = this.public
- }
-
- componentWillUnmount() {
- window.app.layout.floatingStack = null
- delete window.app.layout.floatingStack
- }
-
- render() {
- return
- {
- this.state.renders.map((item) => {
- return
- {item.render}
-
- })
- }
-
- }
-}
-
-export const createWithDom = () => {
- const dom = new DOMWindow({
- id: "FloatingStack",
- })
-
- dom.render()
-
- return dom
-}
\ No newline at end of file
diff --git a/packages/app/src/layouts/components/floatingStack/index.less b/packages/app/src/layouts/components/floatingStack/index.less
deleted file mode 100755
index 0570a2bc..00000000
--- a/packages/app/src/layouts/components/floatingStack/index.less
+++ /dev/null
@@ -1,30 +0,0 @@
-.floating_stack {
- position: absolute;
- z-index: 300;
-
- right: 0;
- bottom: 0;
-
- display: flex;
- flex-direction: column;
-
- align-items: center;
- justify-content: center;
-
- max-width: 450px;
-
- gap: 20px;
-
- margin: 20px;
-
- transition: all 0.3s ease-in-out;
-
- &.hidden {
- transform: translateX(100%);
- opacity: 0;
- }
-}
-
-.floating_stack_item {
- width: 100%;
-}
\ No newline at end of file
diff --git a/packages/app/src/components/Layout/header/index.jsx b/packages/app/src/layouts/components/header/index.jsx
similarity index 100%
rename from packages/app/src/components/Layout/header/index.jsx
rename to packages/app/src/layouts/components/header/index.jsx
diff --git a/packages/app/src/components/Layout/header/index.less b/packages/app/src/layouts/components/header/index.less
similarity index 91%
rename from packages/app/src/components/Layout/header/index.less
rename to packages/app/src/layouts/components/header/index.less
index 5aa4f24a..078c6ee0 100755
--- a/packages/app/src/components/Layout/header/index.less
+++ b/packages/app/src/layouts/components/header/index.less
@@ -12,7 +12,9 @@
width: 100%;
.page_header {
- display: block;
+ display: flex;
+ flex-direction: column;
+
margin: 10px 0 20px 0;
padding: 5px;
diff --git a/packages/app/src/layouts/components/modals/index.jsx b/packages/app/src/layouts/components/modals/index.jsx
index 24f53b76..150387ab 100755
--- a/packages/app/src/layouts/components/modals/index.jsx
+++ b/packages/app/src/layouts/components/modals/index.jsx
@@ -3,7 +3,6 @@ import { Modal as AntdModal } from "antd"
import classnames from "classnames"
import { Icons } from "@components/Icons"
-import { DOMWindow } from "@components/RenderWindow"
import useLayoutInterface from "@hooks/useLayoutInterface"
@@ -118,8 +117,6 @@ export default () => {
render,
{
framed = true,
- frameContentStyle = null,
- includeCloseButton = false,
confirmOnOutsideClick = false,
confirmOnClickTitle,
@@ -129,20 +126,13 @@ export default () => {
props,
} = {}
) {
- const win = new DOMWindow({
- id: id,
- className: className,
- })
-
- win.render( {
- win.destroy()
+ app.cores.window_mng.close(id)
}}
- includeCloseButton={includeCloseButton}
framed={framed}
- frameContentStyle={frameContentStyle}
+ className={className}
confirmOnOutsideClick={confirmOnOutsideClick}
confirmOnClickTitle={confirmOnClickTitle}
confirmOnClickContent={confirmOnClickContent}
diff --git a/packages/app/src/layouts/components/modals/index.less b/packages/app/src/layouts/components/modals/index.less
index 3e30784c..45275f76 100755
--- a/packages/app/src/layouts/components/modals/index.less
+++ b/packages/app/src/layouts/components/modals/index.less
@@ -23,7 +23,7 @@
top: 0;
left: 0;
-
+
width: 100vw;
height: 100vh;
@@ -43,7 +43,7 @@
}
&.active {
- background-color: rgba(var(--bg_color_6), 0.5);
+ background-color: rgba(var(--bg_color_6), 0.1);
backdrop-filter: blur(@modal_background_blur);
-webkit-backdrop-filter: blur(@modal_background_blur);
diff --git a/packages/app/src/components/Layout/quickNav/index.jsx b/packages/app/src/layouts/components/quickNav/index.jsx
similarity index 100%
rename from packages/app/src/components/Layout/quickNav/index.jsx
rename to packages/app/src/layouts/components/quickNav/index.jsx
diff --git a/packages/app/src/components/Layout/sidebar/index.jsx b/packages/app/src/layouts/components/sidebar/index.jsx
similarity index 68%
rename from packages/app/src/components/Layout/sidebar/index.jsx
rename to packages/app/src/layouts/components/sidebar/index.jsx
index a49a658f..523dffb1 100755
--- a/packages/app/src/components/Layout/sidebar/index.jsx
+++ b/packages/app/src/layouts/components/sidebar/index.jsx
@@ -31,6 +31,9 @@ const onClickHandlers = {
search: () => {
window.app.controls.openSearcher()
},
+ messages: () => {
+ window.app.controls.openMessages()
+ },
create: () => {
window.app.controls.openCreator()
},
@@ -63,6 +66,37 @@ const generateTopItems = (extra = []) => {
})
}
+const BottomMenuDefaultItems = [
+ {
+ key: "search",
+ label:
+ {(t) => t("Search")}
+ ,
+ icon: ,
+ },
+ {
+ key: "messages",
+ label:
+ {(t) => t("Messages")}
+ ,
+ icon: ,
+ },
+ {
+ key: "notifications",
+ label:
+ {(t) => t("Notifications")}
+ ,
+ icon: ,
+ },
+ {
+ key: "settings",
+ label:
+ {(t) => t("Settings")}
+ ,
+ icon: ,
+ }
+]
+
const ActionMenuItems = [
{
key: "account",
@@ -268,7 +302,7 @@ export default class Sidebar extends React.Component {
}
handleClick = (e) => {
- if (e.item.props.ignoreClick) {
+ if (e.item.props.ignore_click === "true") {
return
}
@@ -331,144 +365,117 @@ export default class Sidebar extends React.Component {
}
}
+ getBottomItems = () => {
+ const items = [
+ ...BottomMenuDefaultItems,
+ ...this.state.bottomItems,
+ ]
+
+ if (app.userData) {
+ items.push({
+ key: "account",
+ ignore_click: "true",
+ className: "user_avatar",
+ label:
+
+ ,
+ })
+ }
+
+ if (!app.userData) {
+ items.push({
+ key: "login",
+ label:
+ {t => t("Login")}
+ ,
+ icon: ,
+ })
+ }
+
+ return items
+ }
+
render() {
const defaultSelectedKey = window.location.pathname.replace("/", "")
- return <>
-
- {({ x }) => {
- return
+ return
+ {({ x }) => {
+ return
+ visible: this.state.visible,
}
+ )}
+ style={{
+ transform: `translateX(-${x}%)`,
+ }}
+ onMouseEnter={this.onMouseEnter}
+ onMouseLeave={this.handleMouseLeave}
+ >
+ {
+ window.__TAURI__ && navigator.platform.includes("Mac") &&
+ }
-
+ )
+ }
+ ref={this.sidebarRef}
+ >
-
-
-

-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
- }}
-
- >
+
+ }}
+
}
}
\ No newline at end of file
diff --git a/packages/app/src/components/Layout/sidebar/index.less b/packages/app/src/layouts/components/sidebar/index.less
similarity index 93%
rename from packages/app/src/components/Layout/sidebar/index.less
rename to packages/app/src/layouts/components/sidebar/index.less
index 84e1d961..a26c31e7 100755
--- a/packages/app/src/components/Layout/sidebar/index.less
+++ b/packages/app/src/layouts/components/sidebar/index.less
@@ -173,15 +173,27 @@
&.user_avatar {
.ant-menu-title-content {
+ width: 100%;
+
display: inline-flex;
-
+
align-items: flex-start;
justify-content: center;
- width: fit-content;
opacity: 1;
+
+ .ant-dropdown-trigger {
+ width: 100%;
+
+ img {
+ width: fit-content;
+ border-radius: 10px;
+ }
+ }
}
+
+
padding: 0 !important;
}
}
diff --git a/packages/app/src/components/Layout/sidedrawer/index.jsx b/packages/app/src/layouts/components/sidedrawer/index.jsx
similarity index 100%
rename from packages/app/src/components/Layout/sidedrawer/index.jsx
rename to packages/app/src/layouts/components/sidedrawer/index.jsx
diff --git a/packages/app/src/components/Layout/sidedrawer/index.less b/packages/app/src/layouts/components/sidedrawer/index.less
similarity index 100%
rename from packages/app/src/components/Layout/sidedrawer/index.less
rename to packages/app/src/layouts/components/sidedrawer/index.less
diff --git a/packages/app/src/components/Layout/toolsBar/index.jsx b/packages/app/src/layouts/components/toolsBar/index.jsx
similarity index 100%
rename from packages/app/src/components/Layout/toolsBar/index.jsx
rename to packages/app/src/layouts/components/toolsBar/index.jsx
diff --git a/packages/app/src/components/Layout/toolsBar/index.less b/packages/app/src/layouts/components/toolsBar/index.less
similarity index 98%
rename from packages/app/src/components/Layout/toolsBar/index.less
rename to packages/app/src/layouts/components/toolsBar/index.less
index 4e0a6a9e..a34b8e07 100755
--- a/packages/app/src/components/Layout/toolsBar/index.less
+++ b/packages/app/src/layouts/components/toolsBar/index.less
@@ -6,7 +6,7 @@
top: 0;
right: 0;
- max-width: 20vw;
+ max-width: 420px;
min-width: 320px;
height: 100vh;
diff --git a/packages/app/src/components/Layout/topBar/index.jsx b/packages/app/src/layouts/components/topBar/index.jsx
similarity index 100%
rename from packages/app/src/components/Layout/topBar/index.jsx
rename to packages/app/src/layouts/components/topBar/index.jsx
diff --git a/packages/app/src/components/Layout/topBar/index.less b/packages/app/src/layouts/components/topBar/index.less
similarity index 100%
rename from packages/app/src/components/Layout/topBar/index.less
rename to packages/app/src/layouts/components/topBar/index.less
diff --git a/packages/app/src/layouts/default/index.jsx b/packages/app/src/layouts/default/index.jsx
index 3ff362b4..fb864856 100755
--- a/packages/app/src/layouts/default/index.jsx
+++ b/packages/app/src/layouts/default/index.jsx
@@ -2,32 +2,20 @@ import React from "react"
import classnames from "classnames"
import { Layout } from "antd"
-import {
- Sidebar,
- Drawer,
- Sidedrawer,
- BottomBar,
- TopBar,
- ToolsBar,
- Header,
-} from "@components/Layout"
+import Sidebar from "@layouts/components/sidebar"
+import Drawer from "@layouts/components/drawer"
+import Sidedrawer from "@layouts/components/sidedrawer"
+import BottomBar from "@layouts/components/bottomBar"
+import TopBar from "@layouts/components/topBar"
+import ToolsBar from "@layouts/components/toolsBar"
+import Header from "@layouts/components/header"
+import InitializeModalsController from "@layouts/components/modals"
import BackgroundDecorator from "@components/BackgroundDecorator"
-import { createWithDom as FloatingStack } from "../components/floatingStack"
-import InitializeModalsController from "../components/modals"
-
const DesktopLayout = (props) => {
InitializeModalsController()
- React.useEffect(() => {
- const floatingStack = FloatingStack()
-
- return () => {
- floatingStack.remove()
- }
- }, [])
-
return <>
diff --git a/packages/app/src/layouts/minimal/index.jsx b/packages/app/src/layouts/minimal/index.jsx
index 3b71a073..1abc646b 100755
--- a/packages/app/src/layouts/minimal/index.jsx
+++ b/packages/app/src/layouts/minimal/index.jsx
@@ -2,7 +2,8 @@ import React from "react"
import * as antd from "antd"
import classnames from "classnames"
-import { Drawer, Sidedrawer } from "@components/Layout"
+import Drawer from "@layouts/components/drawer"
+import Sidedrawer from "@layouts/components/sidedrawer"
export default (props) => {
return
diff --git a/packages/app/src/pages/account/index.jsx b/packages/app/src/pages/account/index.jsx
index 83035c39..39e342ef 100755
--- a/packages/app/src/pages/account/index.jsx
+++ b/packages/app/src/pages/account/index.jsx
@@ -94,7 +94,6 @@ export default class Account extends React.Component {
})
}
-
onClickFollow = async () => {
const result = await FollowsModel.toggleFollow({
user_id: this.state.user._id,
@@ -183,6 +182,13 @@ export default class Account extends React.Component {
followed={this.state.following}
self={this.state.isSelf}
/>
+
+ {
+ !this.state.isSelf && }
+ onClick={() => app.location.push(`/messages/${user._id}`)}
+ />
+ }
diff --git a/packages/app/src/pages/account/index.less b/packages/app/src/pages/account/index.less
index a832c54b..d9888f58 100755
--- a/packages/app/src/pages/account/index.less
+++ b/packages/app/src/pages/account/index.less
@@ -108,7 +108,9 @@
.actions {
display: flex;
- flex-direction: column;
+ flex-direction: row;
+
+ gap: 10px;
height: fit-content;
width: 20vw;
diff --git a/packages/app/src/pages/auth/forms/selector/index.jsx b/packages/app/src/pages/auth/forms/selector/index.jsx
index 7b38bc30..f47247b7 100755
--- a/packages/app/src/pages/auth/forms/selector/index.jsx
+++ b/packages/app/src/pages/auth/forms/selector/index.jsx
@@ -17,14 +17,14 @@ const MainSelector = (props) => {