mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-10 19:14:16 +00:00
implement ContextMenu
core
This commit is contained in:
parent
f39952baa6
commit
8e81116ba1
@ -0,0 +1,53 @@
|
|||||||
|
import React from "react"
|
||||||
|
|
||||||
|
import { createIconRender } from "components/Icons"
|
||||||
|
|
||||||
|
import "./index.less"
|
||||||
|
|
||||||
|
export default (props) => {
|
||||||
|
const { items = [], cords, clickedComponent } = props
|
||||||
|
|
||||||
|
const handleItemClick = async (item) => {
|
||||||
|
if (typeof item.action === "function") {
|
||||||
|
await item.action(clickedComponent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderItems = () => {
|
||||||
|
if (items.length === 0) {
|
||||||
|
return <div>
|
||||||
|
<p>No items</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
return items.map((item, index) => {
|
||||||
|
if (item.type === "separator") {
|
||||||
|
return <div key={index} className="context-menu-separator" />
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div
|
||||||
|
key={index}
|
||||||
|
onClick={() => handleItemClick(item)}
|
||||||
|
className="item"
|
||||||
|
>
|
||||||
|
<p className="label">
|
||||||
|
{item.label}
|
||||||
|
</p>
|
||||||
|
{item.description && <p className="description">
|
||||||
|
{item.description}
|
||||||
|
</p>}
|
||||||
|
{createIconRender(item.icon)}
|
||||||
|
</div>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div
|
||||||
|
className="contextMenu"
|
||||||
|
style={{
|
||||||
|
top: cords.y,
|
||||||
|
left: cords.x,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{renderItems()}
|
||||||
|
</div>
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
.contextMenu {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 100000;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
width: 200px;
|
||||||
|
height: fit-content;
|
||||||
|
|
||||||
|
background-color: var(--background-color-primary);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
font-family: "Recursive", sans-serif;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-color);
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
p,
|
||||||
|
span {
|
||||||
|
margin: 0;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
padding: 5px 10px 5px 20px;
|
||||||
|
|
||||||
|
transition: all 50ms ease-in-out;
|
||||||
|
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--background-color-accent);
|
||||||
|
padding-left: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: var(--background-color-primary2);
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-menu-separator {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 1px;
|
||||||
|
|
||||||
|
margin: 10px 0;
|
||||||
|
|
||||||
|
background-color: var(--border-color);
|
||||||
|
}
|
||||||
|
}
|
124
packages/app/src/cores/contextMenu/index.js
Normal file
124
packages/app/src/cores/contextMenu/index.js
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
import React from "react"
|
||||||
|
import Core from "evite/src/core"
|
||||||
|
|
||||||
|
import { DOMWindow } from "components/RenderWindow"
|
||||||
|
import ContextMenu from "./components/contextMenu"
|
||||||
|
|
||||||
|
import Contexts from "schemas/menu-contexts"
|
||||||
|
|
||||||
|
export default class ContextMenuCore extends Core {
|
||||||
|
static namespace = "ContextMenu"
|
||||||
|
static public = ["show", "hide", "registerContext"]
|
||||||
|
|
||||||
|
contexts = Object()
|
||||||
|
defaultContext = [
|
||||||
|
{
|
||||||
|
label: "Report a bug",
|
||||||
|
icon: "AlertTriangle",
|
||||||
|
action: (parent, element) => {
|
||||||
|
app.eventBus.emit("app.reportBug", {
|
||||||
|
parent,
|
||||||
|
element
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
DOMWindow = new DOMWindow({
|
||||||
|
id: "contextMenu",
|
||||||
|
className: "contextMenuWrapper",
|
||||||
|
clickOutsideToClose: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
async initialize() {
|
||||||
|
document.addEventListener("contextmenu", this.handleEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
registerContext = (element, context) => {
|
||||||
|
this.contexts[element] = context
|
||||||
|
}
|
||||||
|
|
||||||
|
generateItems = (element) => {
|
||||||
|
let items = []
|
||||||
|
|
||||||
|
// find the closest context with attribute (context-menu)
|
||||||
|
// if not found, use default context
|
||||||
|
const parentElement = element.closest("[context-menu]")
|
||||||
|
|
||||||
|
if (parentElement) {
|
||||||
|
const context = parentElement.getAttribute("context-menu")
|
||||||
|
|
||||||
|
// if context is not registered, try to fetch it from the constants contexts object
|
||||||
|
if (!this.contexts[context]) {
|
||||||
|
items = Contexts[context] || []
|
||||||
|
} else {
|
||||||
|
items = this.contexts[context] ?? []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof items === "function") {
|
||||||
|
items = items(
|
||||||
|
parentElement,
|
||||||
|
element,
|
||||||
|
{
|
||||||
|
close: this.hide
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fullfill each item with a correspondent index if missing declared
|
||||||
|
items = items.map((item, index) => {
|
||||||
|
if (!item.index) {
|
||||||
|
item.index = index
|
||||||
|
}
|
||||||
|
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
|
||||||
|
// short items (if has declared index)
|
||||||
|
items = items.sort((a, b) => a.index - b.index)
|
||||||
|
|
||||||
|
if (items.length > 0) {
|
||||||
|
items.push({
|
||||||
|
type: "separator"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push(...this.defaultContext)
|
||||||
|
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEvent = (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
// get the cords of the mouse
|
||||||
|
const x = event.clientX
|
||||||
|
const y = event.clientY
|
||||||
|
|
||||||
|
// get the component that was clicked
|
||||||
|
const component = document.elementFromPoint(x, y)
|
||||||
|
|
||||||
|
// check if is clicking inside a context menu or a children inside a context menu
|
||||||
|
if (component.classList.contains("contextMenu") || component.closest(".contextMenu")) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.show({
|
||||||
|
cords: {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
},
|
||||||
|
clickedComponent: component,
|
||||||
|
items: this.generateItems(component),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
show = (payload) => {
|
||||||
|
this.DOMWindow.render(React.createElement(ContextMenu, payload))
|
||||||
|
}
|
||||||
|
|
||||||
|
hide = () => {
|
||||||
|
this.DOMWindow.remove()
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ import APICore from "./api"
|
|||||||
import StyleCore from "./style"
|
import StyleCore from "./style"
|
||||||
import PermissionsCore from "./permissions"
|
import PermissionsCore from "./permissions"
|
||||||
import SearchCore from "./search"
|
import SearchCore from "./search"
|
||||||
|
import ContextMenuCore from "./contextMenu"
|
||||||
|
|
||||||
import I18nCore from "./i18n"
|
import I18nCore from "./i18n"
|
||||||
import NotificationsCore from "./notifications"
|
import NotificationsCore from "./notifications"
|
||||||
@ -24,4 +25,5 @@ export default [
|
|||||||
ShortcutsCore,
|
ShortcutsCore,
|
||||||
|
|
||||||
AudioPlayer,
|
AudioPlayer,
|
||||||
|
ContextMenuCore,
|
||||||
]
|
]
|
Loading…
x
Reference in New Issue
Block a user