diff --git a/app/src/assets/scss/base.scss b/app/src/assets/scss/base.scss index 1999c379d..cca324764 100644 --- a/app/src/assets/scss/base.scss +++ b/app/src/assets/scss/base.scss @@ -32,6 +32,7 @@ @import "business/card"; @import "business/custom"; @import "business/resize"; +@import "business/av"; /* .status: 2 @@ -69,6 +70,8 @@ ctrl+p 搜索: 202 // 移动端排序和菜单需临时大于 .side-panel https://github.com/siyuan-note/siyuan/issues/5254 .b3-menu: 310 +.av__mask: 320 + // 需大于 .b3-dialog progressLoading: 400 diff --git a/app/src/assets/scss/business/_av.scss b/app/src/assets/scss/business/_av.scss new file mode 100644 index 000000000..a994d9044 --- /dev/null +++ b/app/src/assets/scss/business/_av.scss @@ -0,0 +1,59 @@ +.av { + &__mask { + position: fixed; + z-index: 320; + top: 0; + bottom: 0; + right: 0; + left: 0; + } + + &__scroll { + overflow: auto hidden; + cursor: pointer; + } + + &__row { + display: flex; + border-bottom: 1px solid var(--b3-theme-surface-lighter); + + &--header .av__cell { + display: flex; + align-items: center; + + svg { + height: 14px; + width: 14px; + color: var(--b3-theme-on-surface); + margin-right: 5px; + } + } + + &--header, + &--footer { + background-color: var(--b3-theme-background); + } + } + + &__cell { + padding: 5px; + flex-shrink: 0; + border-right: 1px solid var(--b3-theme-surface-lighter) + } + + &__firstcol { + svg { + color: var(--b3-theme-on-surface); + height: 36px; + width: 24px; + opacity: 0; + padding: 5px; + box-sizing: border-box; + float: left; + } + + &:hover svg { + opacity: 1; + } + } +} diff --git a/app/src/assets/scss/mobile.scss b/app/src/assets/scss/mobile.scss index 87b3a48dd..5def066b8 100644 --- a/app/src/assets/scss/mobile.scss +++ b/app/src/assets/scss/mobile.scss @@ -24,6 +24,7 @@ @import "business/export"; @import "business/card"; @import "business/custom"; +@import "business/av"; .block__popover { width: 80vw; diff --git a/app/src/assets/scss/protyle/_wysiwyg.scss b/app/src/assets/scss/protyle/_wysiwyg.scss index 3c715be7b..4547dd37c 100644 --- a/app/src/assets/scss/protyle/_wysiwyg.scss +++ b/app/src/assets/scss/protyle/_wysiwyg.scss @@ -30,59 +30,6 @@ } } - &.av { - .av { - &__scroll { - overflow: auto hidden; - cursor: pointer; - } - - &__row { - display: flex; - border-bottom: 1px solid var(--b3-theme-surface-lighter); - - &--header .av__cell { - display: flex; - align-items: center; - - svg { - height: 14px; - width: 14px; - color: var(--b3-theme-on-surface); - margin-right: 5px; - } - } - - &--header, - &--footer { - background-color: var(--b3-theme-background); - } - } - - &__cell { - padding: 5px; - flex-shrink: 0; - border-right: 1px solid var(--b3-theme-surface-lighter) - } - - &__firstcol { - svg { - color: var(--b3-theme-on-surface); - height: 36px; - width: 24px; - opacity: 0; - padding: 5px; - box-sizing: border-box; - float: left; - } - - &:hover svg { - opacity: 1; - } - } - } - } - &.hr { cursor: pointer; diff --git a/app/src/boot/globalShortcut.ts b/app/src/boot/globalShortcut.ts index 5434362b1..49b84c138 100644 --- a/app/src/boot/globalShortcut.ts +++ b/app/src/boot/globalShortcut.ts @@ -391,7 +391,7 @@ export const globalShortcut = (app: App) => { }); window.addEventListener("keydown", (event) => { - if (document.getElementById("errorLog") || event.isComposing) { + if (document.querySelector(".av__mask") || document.getElementById("errorLog") || event.isComposing) { return; } const target = event.target as HTMLElement; diff --git a/app/src/protyle/render/av/action.ts b/app/src/protyle/render/av/action.ts index d3275a967..cea105440 100644 --- a/app/src/protyle/render/av/action.ts +++ b/app/src/protyle/render/av/action.ts @@ -42,8 +42,8 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle const cellElement = hasClosestByClassName(event.target, "av__cell"); if (cellElement && blockElement) { - const type = cellElement.getAttribute("data-dtype") as TAVCol; if (cellElement.parentElement.classList.contains("av__row--header")) { + const type = cellElement.getAttribute("data-dtype") as TAVCol; const menu = new Menu("av-header-cell"); menu.addItem({ icon: getIconByType(type), @@ -136,7 +136,7 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle event.preventDefault(); event.stopPropagation(); } else { - popTextCell() + popTextCell(protyle, cellElement) } return true; } @@ -217,3 +217,8 @@ export const avContextmenu = (protyle: IProtyle, event: MouseEvent & { detail: a event.stopPropagation(); return true; } + + +const addRow = () => { + +} diff --git a/app/src/protyle/render/av/cell.ts b/app/src/protyle/render/av/cell.ts index 9a3315f75..ea4c6b434 100644 --- a/app/src/protyle/render/av/cell.ts +++ b/app/src/protyle/render/av/cell.ts @@ -1,3 +1,66 @@ -export const popTextCell = () => { +import {transaction} from "../../wysiwyg/transaction"; +import {hasClosestBlock} from "../../util/hasClosest"; +export const popTextCell = (protyle: IProtyle, cellElement: HTMLElement) => { + const index = parseInt(cellElement.getAttribute("data-index")) + const tableElement = cellElement.parentElement.parentElement + const colCellElement = tableElement.firstElementChild.children[index + 1]; + const type = colCellElement.getAttribute("data-dtype") as TAVCol; + const cellRect = cellElement.getBoundingClientRect() + let html = "" + if (type === "block") { + html = ``; + } + document.body.insertAdjacentHTML("beforeend", `
+ ${html} +
`); + const avMaskElement = document.querySelector(".av__mask"); + const inputElement = avMaskElement.querySelector(".b3-text-field") as HTMLInputElement; + if (inputElement) { + inputElement.select(); + inputElement.addEventListener("blur", () => { + updateCellValue(protyle, cellElement, type) + }) + inputElement.addEventListener("keydown", (event) => { + if (event.isComposing) { + return + } + if (event.key === "Escape" || event.key === "Enter") { + updateCellValue(protyle, cellElement, type) + event.preventDefault(); + event.stopPropagation(); + } + }) + } + avMaskElement.addEventListener("click", (event) => { + if ((event.target as HTMLElement).classList.contains("av__mask")) { + avMaskElement?.remove(); + } + }) +}; + + +const updateCellValue = (protyle: IProtyle, cellElement: HTMLElement, type: TAVCol) => { + const avMaskElement = document.querySelector(".av__mask"); + const inputElement = avMaskElement.querySelector(".b3-text-field") as HTMLInputElement; + const blockElement = hasClosestBlock(cellElement) + if (!blockElement) { + return + } + transaction(protyle, [{ + action: "updateAttrViewCell", + id: blockElement.getAttribute("data-node-id"), + rowID: blockElement.getAttribute("data-av-id"), + type, + data: inputElement.value, + }], [{ + action: "updateAttrViewCell", + id: blockElement.getAttribute("data-node-id"), + rowID: blockElement.getAttribute("data-av-id"), + type, + data: cellElement.textContent.trim(), + }]); + setTimeout(() => { + avMaskElement.remove(); + }) } diff --git a/app/src/protyle/render/av/render.ts b/app/src/protyle/render/av/render.ts index d9d2cdf28..c5fd8919b 100644 --- a/app/src/protyle/render/av/render.ts +++ b/app/src/protyle/render/av/render.ts @@ -49,7 +49,7 @@ export const avRender = (element: Element) => { data.rows.forEach((row: IAVRow) => { tableHTML += `
`; row.cells.forEach((cell, index) => { - tableHTML += `
${cell.value}
`; + tableHTML += `
${cell.value}
`; }); tableHTML += "
"; }); diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index 0139ff992..4bbc0745c 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -22,6 +22,7 @@ type TOperation = | "removeAttrViewCol" | "addFlashcards" | "removeFlashcards" + | "updateAttrViewCell" type TBazaarType = "templates" | "icons" | "widgets" | "themes" | "plugins" type TCardType = "doc" | "notebook" | "all" type TEventBus = "ws-main" | "click-blockicon" | "click-editorcontent" | "click-pdf" | @@ -283,6 +284,7 @@ interface IOperation { srcIDs?: string[] // insertAttrViewBlock 专享 name?: string // addAttrViewCol 专享 type?: TAVCol // addAttrViewCol 专享 + rowID?: string // updateAttrViewCell 专享 deckID?: string // add/removeFlashcards 专享 blockIDs?: string[] // add/removeFlashcards 专享 }