Vanessa 2023-07-02 20:52:16 +08:00
parent 593959312d
commit 22c46bbc6b
10 changed files with 283 additions and 118 deletions

View file

@ -78,6 +78,8 @@ progressLoading: 400
#windowControls: 502
.b3-snackbar: 503
.av__panel: 504
*/
html {

View file

@ -12,6 +12,7 @@
outline: none;
font-size: 18px;
font-weight: bold;
&:empty::after {
color: var(--b3-theme-on-surface);
content: attr(data-tip);
@ -109,6 +110,15 @@
}
}
&__panel {
z-index: 504;
position: relative;
.b3-menu__item:not([data-type="title"]):hover {
background-color: var(--b3-list-hover);
}
}
&.protyle-wysiwyg--select {
.layout-tab-bar,
.av__row--header,

View file

@ -231,6 +231,7 @@
&:hover {
opacity: 1;
color: var(--b3-theme-on-background);
}
}

View file

@ -874,7 +874,8 @@ export const globalShortcut = (app: App) => {
window.addEventListener("click", (event: MouseEvent & { target: HTMLElement }) => {
if (!window.siyuan.menus.menu.element.contains(event.target) && !hasClosestByAttribute(event.target, "data-menu", "true")) {
if (getSelection().rangeCount > 0 && window.siyuan.menus.menu.element.contains(getSelection().getRangeAt(0).startContainer)) {
if (getSelection().rangeCount > 0 && window.siyuan.menus.menu.element.contains(getSelection().getRangeAt(0).startContainer) &&
window.siyuan.menus.menu.element.contains(document.activeElement)) {
// https://ld246.com/article/1654567749834/comment/1654589171218#comments
} else {
window.siyuan.menus.menu.remove();

View file

@ -46,11 +46,11 @@ export const hintSlash = (key: string, protyle: IProtyle) => {
filter: ["ai chat"],
value: Constants.ZWSP + 5,
html: '<div class="b3-list-item__first"><svg class="b3-list-item__graphic"><use xlink:href="#iconSparkles"></use></svg><span class="b3-list-item__text">AI Chat</span></div>',
}, {
}, /*{
filter: ["属性视图", "shuxingshitu", "sxst", "attribute view"],
value: '<div data-type="NodeAttributeView" data-av-type="table"></div>',
html: `<div class="b3-list-item__first"><svg class="b3-list-item__graphic"><use xlink:href="#iconDatabase"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.attributeView}</span></div>`,
}, {
},*/ {
filter: ["文档", "子文档", "wendang", "wd", "ziwendang", "zwd", "xjwd"],
value: Constants.ZWSP + 4,
html: `<div class="b3-list-item__first"><svg class="b3-list-item__graphic"><use xlink:href="#iconFile"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.newFile}</span><span class="b3-menu__accelerator">${updateHotkeyTip(window.siyuan.config.keymap.general.newFile.custom)}</span></div>`,

View file

@ -6,6 +6,8 @@ import {copySubMenu} from "../../../menus/commonMenuItem";
import {popTextCell, showHeaderCellMenu} from "./cell";
import {getColIconByType, updateHeader} from "./col";
import {emitOpenMenu} from "../../../plugin/EventBus";
import {addCol} from "./addCol";
import {openMenuPanel} from "./openMenuPanel";
export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLElement }) => {
const blockElement = hasClosestBlock(event.target);
@ -14,108 +16,7 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle
}
const addElement = hasClosestByAttribute(event.target, "data-type", "av-header-add");
if (addElement) {
const menu = new Menu("av-header-add");
menu.addItem({
icon: "iconAlignLeft",
label: window.siyuan.languages.text,
click() {
const id = Lute.NewNodeID();
const type = "text";
transaction(protyle, [{
action: "addAttrViewCol",
name: "Text",
parentID: blockElement.getAttribute("data-av-id"),
type,
id
}], [{
action: "removeAttrViewCol",
id,
parentID: blockElement.getAttribute("data-av-id"),
}]);
}
});
menu.addItem({
icon: "iconNumber",
label: window.siyuan.languages.number,
click() {
const id = Lute.NewNodeID();
const type = "text";
transaction(protyle, [{
action: "addAttrViewCol",
name: "Text",
parentID: blockElement.getAttribute("data-av-id"),
type,
id
}], [{
action: "removeAttrViewCol",
id,
parentID: blockElement.getAttribute("data-av-id"),
}]);
}
});
menu.addItem({
icon: "iconListItem",
label: window.siyuan.languages.select,
click() {
const id = Lute.NewNodeID();
const type = "text";
transaction(protyle, [{
action: "addAttrViewCol",
name: "Text",
parentID: blockElement.getAttribute("data-av-id"),
type,
id
}], [{
action: "removeAttrViewCol",
id,
parentID: blockElement.getAttribute("data-av-id"),
}]);
}
});
menu.addItem({
icon: "iconList",
label: window.siyuan.languages.multiSelect,
click() {
const id = Lute.NewNodeID();
const type = "text";
transaction(protyle, [{
action: "addAttrViewCol",
name: "Text",
parentID: blockElement.getAttribute("data-av-id"),
type,
id
}], [{
action: "removeAttrViewCol",
id,
parentID: blockElement.getAttribute("data-av-id"),
}]);
}
});
menu.addItem({
icon: "iconCalendar",
label: window.siyuan.languages.date,
click() {
const id = Lute.NewNodeID();
const type = "text";
transaction(protyle, [{
action: "addAttrViewCol",
name: "Text",
parentID: blockElement.getAttribute("data-av-id"),
type,
id
}], [{
action: "removeAttrViewCol",
id,
parentID: blockElement.getAttribute("data-av-id"),
}]);
}
});
const addRect = addElement.getBoundingClientRect();
menu.open({
x: addRect.left,
y: addRect.bottom,
h: addRect.height
});
addCol(protyle, blockElement, addElement);
event.preventDefault();
event.stopPropagation();
return true;
@ -161,6 +62,21 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle
return true;
}
const headerMoreElement = hasClosestByAttribute(event.target, "data-type","av-header-more");
if (headerMoreElement) {
openMenuPanel(protyle, blockElement, "properties");
event.preventDefault();
event.stopPropagation();
return true;
}
const moreElement = hasClosestByAttribute(event.target, "data-type","av-more");
if (moreElement) {
openMenuPanel(protyle, blockElement, "config");
event.preventDefault();
event.stopPropagation();
return true;
}
const cellElement = hasClosestByClassName(event.target, "av__cell");
if (cellElement) {
if (cellElement.parentElement.classList.contains("av__row--header")) {

View file

@ -0,0 +1,107 @@
import {Menu} from "../../../plugin/Menu";
import {transaction} from "../../wysiwyg/transaction";
export const addCol = (protyle:IProtyle, blockElement:HTMLElement, addElement:HTMLElement) => {
const menu = new Menu("av-header-add");
menu.addItem({
icon: "iconAlignLeft",
label: window.siyuan.languages.text,
click() {
const id = Lute.NewNodeID();
const type = "text";
transaction(protyle, [{
action: "addAttrViewCol",
name: "Text",
parentID: blockElement.getAttribute("data-av-id"),
type,
id
}], [{
action: "removeAttrViewCol",
id,
parentID: blockElement.getAttribute("data-av-id"),
}]);
}
});
menu.addItem({
icon: "iconNumber",
label: window.siyuan.languages.number,
click() {
const id = Lute.NewNodeID();
const type = "text";
transaction(protyle, [{
action: "addAttrViewCol",
name: "Text",
parentID: blockElement.getAttribute("data-av-id"),
type,
id
}], [{
action: "removeAttrViewCol",
id,
parentID: blockElement.getAttribute("data-av-id"),
}]);
}
});
menu.addItem({
icon: "iconListItem",
label: window.siyuan.languages.select,
click() {
const id = Lute.NewNodeID();
const type = "text";
transaction(protyle, [{
action: "addAttrViewCol",
name: "Text",
parentID: blockElement.getAttribute("data-av-id"),
type,
id
}], [{
action: "removeAttrViewCol",
id,
parentID: blockElement.getAttribute("data-av-id"),
}]);
}
});
menu.addItem({
icon: "iconList",
label: window.siyuan.languages.multiSelect,
click() {
const id = Lute.NewNodeID();
const type = "text";
transaction(protyle, [{
action: "addAttrViewCol",
name: "Text",
parentID: blockElement.getAttribute("data-av-id"),
type,
id
}], [{
action: "removeAttrViewCol",
id,
parentID: blockElement.getAttribute("data-av-id"),
}]);
}
});
menu.addItem({
icon: "iconCalendar",
label: window.siyuan.languages.date,
click() {
const id = Lute.NewNodeID();
const type = "text";
transaction(protyle, [{
action: "addAttrViewCol",
name: "Text",
parentID: blockElement.getAttribute("data-av-id"),
type,
id
}], [{
action: "removeAttrViewCol",
id,
parentID: blockElement.getAttribute("data-av-id"),
}]);
}
});
const addRect = addElement.getBoundingClientRect();
menu.open({
x: addRect.left,
y: addRect.bottom,
h: addRect.height
});
}

View file

@ -89,6 +89,8 @@ const removeCol = (cellElement: HTMLElement) => {
export const showHeaderCellMenu = (protyle: IProtyle, blockElement: HTMLElement, cellElement: HTMLElement) => {
const type = cellElement.getAttribute("data-dtype") as TAVCol;
const colId = cellElement.getAttribute("data-id");
const avId = blockElement.getAttribute("data-av-id");
const menu = new Menu("av-header-cell", () => {
const newValue = (window.siyuan.menus.menu.element.querySelector(".b3-text-field") as HTMLInputElement).value;
if (newValue === cellElement.textContent.trim()) {
@ -96,14 +98,14 @@ export const showHeaderCellMenu = (protyle: IProtyle, blockElement: HTMLElement,
}
transaction(protyle, [{
action: "updateAttrViewCol",
id: cellElement.getAttribute("data-id"),
parentID: blockElement.getAttribute("data-av-id"),
id: colId,
parentID: avId,
name: newValue,
type,
}], [{
action: "updateAttrViewCol",
id: cellElement.getAttribute("data-id"),
parentID: blockElement.getAttribute("data-av-id"),
id: colId,
parentID: avId,
name: cellElement.textContent.trim(),
type,
}]);
@ -150,10 +152,14 @@ export const showHeaderCellMenu = (protyle: IProtyle, blockElement: HTMLElement,
label: window.siyuan.languages.hide,
click() {
transaction(protyle, [{
action:"setAttrViewColHidden",
action: "setAttrViewColHidden",
id: colId,
parentID: avId,
data: true
}], [{
action:"setAttrViewColHidden",
action: "setAttrViewColHidden",
id: colId,
parentID: avId,
data: false
}]);
}
@ -169,17 +175,16 @@ export const showHeaderCellMenu = (protyle: IProtyle, blockElement: HTMLElement,
icon: "iconTrashcan",
label: window.siyuan.languages.delete,
click() {
const id = cellElement.getAttribute("data-id");
transaction(protyle, [{
action: "removeAttrViewCol",
id,
parentID: blockElement.getAttribute("data-av-id"),
id: colId,
parentID: avId,
}], [{
action: "addAttrViewCol",
name: cellElement.textContent.trim(),
parentID: blockElement.getAttribute("data-av-id"),
parentID: avId,
type: type,
id
id: colId
}]);
removeCol(cellElement);
}
@ -199,5 +204,9 @@ export const showHeaderCellMenu = (protyle: IProtyle, blockElement: HTMLElement,
y: cellRect.bottom,
h: cellRect.height
});
(window.siyuan.menus.menu.element.querySelector(".b3-text-field") as HTMLInputElement)?.select();
const inputElement = window.siyuan.menus.menu.element.querySelector(".b3-text-field") as HTMLInputElement
if (inputElement) {
inputElement.select();
inputElement.focus();
}
};

View file

@ -0,0 +1,103 @@
import {Menu} from "../../../plugin/Menu";
import {transaction} from "../../wysiwyg/transaction";
import {fetchPost} from "../../../util/fetch";
import {hideElements} from "../../ui/hideElements";
export const openMenuPanel = (protyle: IProtyle, blockElement: HTMLElement, type: "properties" | "config" = "config") => {
let avMenuPanel = document.querySelector(".av__panel");
if (avMenuPanel) {
avMenuPanel.remove();
return;
}
window.siyuan.menus.menu.remove();
fetchPost("/api/av/renderAttributeView", {id: blockElement.getAttribute("data-av-id")}, (response) => {
const data = response.data.av;
const tabRect = blockElement.querySelector(".layout-tab-bar").getBoundingClientRect()
let html
if (type === "config") {
html = `<div class="av__panel">
<div class="b3-dialog__scrim" data-type="close"></div>
<div class="b3-menu" style="width: 300px;right:${window.innerWidth - tabRect.right}px;top:${tabRect.bottom}px">
<button class="b3-menu__item" data-type="title">
<span class="b3-menu__label">${window.siyuan.languages.config}</span>
<svg class="b3-menu__action" data-type="close" style="opacity: 1"><use xlink:href="#iconCloseRound"></use></svg>
</button>
<button class="b3-menu__item">
<svg class="b3-menu__icon"></svg>
<span class="b3-menu__label">${window.siyuan.languages.attr}</span>
<span class="b3-menu__accelerator">${data.columns.filter((item: IAVColumn) => !item.hidden).length}/${data.columns.length}</span>
<svg class="b3-menu__icon b3-menu__icon--arrow"><use xlink:href="#iconRight"></use></svg>
</button>
<button class="b3-menu__item">
<svg class="b3-menu__icon"><use xlink:href="#iconFilter"></use></svg>
<span class="b3-menu__label">${window.siyuan.languages.filter}</span>
<span class="b3-menu__accelerator">${data.filters.length}</span>
<svg class="b3-menu__icon b3-menu__icon--arrow"><use xlink:href="#iconRight"></use></svg>
</button>
<button class="b3-menu__item">
<svg class="b3-menu__icon"><use xlink:href="#iconSort"></use></svg>
<span class="b3-menu__label">${window.siyuan.languages.sort}</span>
<span class="b3-menu__accelerator">${data.sorts.length}</span>
<svg class="b3-menu__icon b3-menu__icon--arrow"><use xlink:href="#iconRight"></use></svg>
</button>
<button class="b3-menu__item">
<svg class="b3-menu__icon"></svg>
<span class="b3-menu__label">${window.siyuan.languages.pageCount}</span>
<span class="b3-menu__accelerator">50</span>
<svg class="b3-menu__icon b3-menu__icon--arrow"><use xlink:href="#iconRight"></use></svg>
</button>
</div>
</div>`
} else if (type === "properties") {
html = `<div class="av__panel">
<div class="b3-dialog__scrim" data-type="close"></div>
<div class="b3-menu" style="width: 300px;right:${window.innerWidth - tabRect.right}px;top:${tabRect.bottom}px">
<button class="b3-menu__item">
<svg class="b3-menu__icon"><use xlink:href="#iconLeft"></use></svg>
<span class="b3-menu__label">${window.siyuan.languages.attr}</span>
<svg class="b3-menu__action" data-type="close" style="opacity: 1"><use xlink:href="#iconCloseRound"></use></svg>
</button>
<button class="b3-menu__item">
<svg class="b3-menu__icon"></svg>
<span class="b3-menu__label">${window.siyuan.languages.attr}</span>
<span class="b3-menu__accelerator">${data.columns.filter((item: IAVColumn) => !item.hidden).length}/${data.columns.length}</span>
<svg class="b3-menu__icon b3-menu__icon--arrow"><use xlink:href="#iconRight"></use></svg>
</button>
<button class="b3-menu__item">
<svg class="b3-menu__icon"><use xlink:href="#iconFilter"></use></svg>
<span class="b3-menu__label">${window.siyuan.languages.filter}</span>
<span class="b3-menu__accelerator">${data.filters.length}</span>
<svg class="b3-menu__icon b3-menu__icon--arrow"><use xlink:href="#iconRight"></use></svg>
</button>
<button class="b3-menu__item">
<svg class="b3-menu__icon"><use xlink:href="#iconSort"></use></svg>
<span class="b3-menu__label">${window.siyuan.languages.sort}</span>
<span class="b3-menu__accelerator">${data.sorts.length}</span>
<svg class="b3-menu__icon b3-menu__icon--arrow"><use xlink:href="#iconRight"></use></svg>
</button>
<button class="b3-menu__item">
<svg class="b3-menu__icon"></svg>
<span class="b3-menu__label">${window.siyuan.languages.pageCount}</span>
<span class="b3-menu__accelerator">50</span>
<svg class="b3-menu__icon b3-menu__icon--arrow"><use xlink:href="#iconRight"></use></svg>
</button>
</div>
</div>`
}
document.body.insertAdjacentHTML("beforeend", html);
avMenuPanel = document.querySelector(".av__panel");
avMenuPanel.addEventListener("click", (event) => {
event.preventDefault();
event.stopPropagation();
let target = event.target as HTMLElement;
while (target && !target.isSameNode(avMenuPanel)) {
const type = target.dataset.type;
if (type === "close") {
avMenuPanel.remove();
break;
}
target = target.parentElement;
}
});
});
}

View file

@ -49,6 +49,9 @@ export const avRender = (element: Element, cb?: () => void) => {
</div>
<div class="av__firstcol"><svg><use xlink:href="#iconUncheck"></use></svg></div>`;
row.cells.forEach((cell, index) => {
if (data.columns[index].hidden) {
return;
}
let text: string;
if (cell.valueType === "text") {
text = cell.value?.text.content || "";
@ -78,8 +81,21 @@ export const avRender = (element: Element, cb?: () => void) => {
<svg class="item__graphic"><use xlink:href="#iconTable"></use></svg>
<span class="item__text">Table</span>
</div>
<div class="fn__flex-1"></div>
<span data-type="av-filter" class="block__icon block__icon--show b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.filter}">
<svg><use xlink:href="#iconFilter"></use></svg>
</span>
<div class="fn__space"></div>
<span data-type="av-sort" class="block__icon block__icon--show b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.sort}">
<svg><use xlink:href="#iconSort"></use></svg>
</span>
<div class="fn__space"></div>
<span data-type="av-more" class="block__icon block__icon--show b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.more}">
<svg><use xlink:href="#iconMore"></use></svg>
</span>
<div class="fn__space"></div>
</div>
<div contenteditable="true" class="av__title" data-tip="${window.siyuan.languages.title}">${data.title||""}</div>
<div contenteditable="true" class="av__title" data-tip="${window.siyuan.languages.title}">${data.title || ""}</div>
<div class="av__counter fn__none"></div>
</div>
<div class="av__scroll">