diff --git a/app/appearance/themes/daylight/theme.css b/app/appearance/themes/daylight/theme.css index 5da07510a..685522a20 100644 --- a/app/appearance/themes/daylight/theme.css +++ b/app/appearance/themes/daylight/theme.css @@ -55,6 +55,10 @@ --b3-tooltips-color: var(--b3-theme-background-light); --b3-tooltips-shadow: 0 2px 8px rgba(0, 0, 0, .1); + /* av */ + --b3-av-hover: #e8e8e9; + --b3-av-background-hl: #e8eefc; + /* 为空提示 */ --b3-empty-color: var(--b3-theme-on-surface-light); @@ -92,11 +96,11 @@ --b3-font-background5: #e2e3e4; --b3-font-background6: #acd0fc; --b3-font-background7: #fdeed6; - --b3-font-background8: rgba(255, 193, 153, 0.5); + --b3-font-background8: #fae1cf; --b3-font-background9: #fdd5e7; --b3-font-background10: #e6c7e6; --b3-font-background11: #def0d9; - --b3-font-background12: rgba(253, 198, 200, 0.5); + --b3-font-background12: #fae3e4; --b3-font-background13: var(--b3-theme-on-background); /* 动画效果 */ diff --git a/app/appearance/themes/midnight/theme.css b/app/appearance/themes/midnight/theme.css index a95db4980..a270a6013 100644 --- a/app/appearance/themes/midnight/theme.css +++ b/app/appearance/themes/midnight/theme.css @@ -55,6 +55,10 @@ --b3-tooltips-color: var(--b3-theme-on-surface-light); --b3-tooltips-shadow: 0 2px 8px rgba(0, 0, 0, .3); + /* av */ + --b3-av-hover: #2a2a2a; + --b3-av-background-hl: #28324e; + /* 为空提示 */ --b3-empty-color: var(--b3-theme-on-surface); diff --git a/app/src/assets/scss/business/_av.scss b/app/src/assets/scss/business/_av.scss index 8ca476f22..23ac57c3f 100644 --- a/app/src/assets/scss/business/_av.scss +++ b/app/src/assets/scss/business/_av.scss @@ -11,6 +11,7 @@ &__pulse { width: 70%; height: 23px; + display: block; position: relative; overflow: hidden; background: var(--b3-border-color); @@ -29,10 +30,6 @@ } } - &:hover .av__row--footer > .av__calc--show { - opacity: 1; - } - &__header { top: -43px; z-index: 2; @@ -61,7 +58,7 @@ bottom: 0; height: 30px; padding: 0 5px; - background-color: var(--b3-theme-background); + background-color: var(--av-background); } &__gutters { @@ -116,7 +113,9 @@ } &--select { - background-color: var(--b3-theme-primary-lightest); + .av__cell { + background-color: var(--b3-av-hover); + } .av__firstcol svg { opacity: 1; @@ -124,39 +123,45 @@ } &--header { - z-index: 1; + z-index: 3; .av__cell { padding: 0; transition: background 20ms ease-in 0s; display: flex; + overflow: inherit; // 保证列宽和顺序调整的拖拽点样式 &:hover { - background-color: var(--b3-list-icon-hover); + background-color: var(--b3-av-hover); } } } &--header, &--footer { - background-color: var(--b3-theme-background); + background-color: var(--av-background); } &--footer { display: flex; border-top: 1px solid var(--b3-theme-surface-lighter); color: var(--b3-theme-on-surface); + position: relative; + z-index: 2; - &:hover > .av__calc, - &.av__row--show > .av__calc { + &:hover .av__calc, + &.av__row--show .av__calc { opacity: 1; } - & > .av__calc { - transition: opacity 150ms linear, background 20ms ease-in 0s; + .av__colsticky { + background-color: var(--av-background); // 保证盯住时无计算结果的列不被覆盖 + } + + .av__calc { display: flex; align-items: center; - padding: 5px 5px 5px 7px; + padding: 5px; border-right: 1px; flex-direction: row-reverse; box-sizing: border-box; @@ -181,29 +186,32 @@ } &:hover { - background-color: var(--b3-list-icon-hover); + background-color: var(--b3-av-hover); } } } &--add { color: var(--b3-theme-on-surface); - padding: 5px 5px 5px 7px; - display: flex; - align-items: center; transition: background 20ms ease-in 0s; font-size: 87.5%; + align-items: center; + display: flex; - svg { - height: 12px; - width: 12px; - color: var(--b3-theme-on-surface); - margin-right: 5px; - flex-shrink: 0; + .av__colsticky { + align-items: center; + + svg { + height: 14px; + width: 14px; + color: var(--b3-theme-on-surface); + padding: 10px 10px 10px 5px; + flex-shrink: 0; + } } &:hover { - background-color: var(--b3-list-icon-hover); + background-color: var(--b3-av-hover); } } } @@ -300,6 +308,18 @@ } } + &__colsticky { + position: sticky; + left: 0; + z-index: 1; + display: flex; + + &.av__firstcol, + & > div { + background-color: var(--av-background); + } + } + &__widthdrag { position: absolute; cursor: col-resize; @@ -382,7 +402,30 @@ .protyle-wysiwyg--select, .protyle-wysiwyg--hl { .av__row--header, - .av__row--footer { + .av__row--footer, + .av__row--footer .av__colsticky, + .av__row--select .av__cell, + .av__colsticky.av__firstcol, + .av__colsticky > div, + .av__counter { + background-color: var(--b3-av-background-hl); + } +} + +.dragover__top, +.dragover__bottom { + .av__colsticky { + z-index: 0; + + & > div { + background-color: transparent; + } + } +} + +.dragover__bottom + .av__row, +.av__row:has(+ .dragover__top) { + .av__colsticky > div { background-color: transparent; } } diff --git a/app/src/assets/scss/business/_custom.scss b/app/src/assets/scss/business/_custom.scss index 4b56e8287..922482428 100644 --- a/app/src/assets/scss/business/_custom.scss +++ b/app/src/assets/scss/business/_custom.scss @@ -38,6 +38,8 @@ .block__icons { min-height: auto; padding: 4px 8px; + font-size: 100%; + border-bottom: 0; } .b3-text-field--text { diff --git a/app/src/block/popover.ts b/app/src/block/popover.ts index f96cb306c..3d0241822 100644 --- a/app/src/block/popover.ts +++ b/app/src/block/popover.ts @@ -22,7 +22,7 @@ export const initBlockPopover = (app: App) => { if (aElement) { let tip = aElement.getAttribute("aria-label") || aElement.getAttribute("data-inline-memo-content"); if (aElement.classList.contains("av__celltext")) { - if (aElement.scrollWidth > aElement.parentElement.clientWidth - 11) { + if (aElement.offsetWidth > aElement.parentElement.clientWidth - 11) { if (aElement.querySelector(".av__cellicon")) { tip = `${aElement.firstChild.textContent} ➡️ ${aElement.lastChild.textContent}`; } else { diff --git a/app/src/boot/globalEvent/keydown.ts b/app/src/boot/globalEvent/keydown.ts index 53b3a9c7d..3f865c194 100644 --- a/app/src/boot/globalEvent/keydown.ts +++ b/app/src/boot/globalEvent/keydown.ts @@ -1270,15 +1270,20 @@ export const windowKeyDown = (app: App, event: KeyboardEvent) => { } } - if (window.siyuan.dialogs.length > 0) { - window.siyuan.dialogs[window.siyuan.dialogs.length - 1].destroy(); + // 需放在 menus 后,否则资源列中添加资源会先关闭菜单 + // 需放在 dialog 前,否则属性面板中修改日期会先关闭 dialog,只剩修改界面 + const avElement = document.querySelector(".av__panel"); + if (avElement) { + const selectCellElement = document.querySelector(".av__cell--select") + if (selectCellElement) { + focusBlock(hasClosestBlock(selectCellElement) as HTMLElement); + } + avElement.remove(); return; } - // 需放在 menus 后,否则资源列中添加资源会先关闭菜单 - const avElement = document.querySelector(".av__panel"); - if (avElement) { - avElement.remove(); + if (window.siyuan.dialogs.length > 0) { + window.siyuan.dialogs[window.siyuan.dialogs.length - 1].destroy(); return; } diff --git a/app/src/menus/Menu.ts b/app/src/menus/Menu.ts index cb2080a9d..9bf2fef10 100644 --- a/app/src/menus/Menu.ts +++ b/app/src/menus/Menu.ts @@ -1,4 +1,4 @@ -import {getEventName, isCtrl, updateHotkeyTip} from "../protyle/util/compatibility"; +import {getEventName, updateHotkeyTip} from "../protyle/util/compatibility"; import {setPosition} from "../util/setPosition"; import {hasClosestByClassName} from "../protyle/util/hasClosest"; import {isMobile} from "../util/functions"; diff --git a/app/src/protyle/render/av/action.ts b/app/src/protyle/render/av/action.ts index 44dfdcf56..cb3bf2b0e 100644 --- a/app/src/protyle/render/av/action.ts +++ b/app/src/protyle/render/av/action.ts @@ -3,7 +3,7 @@ import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName} from "../ import {transaction} from "../../wysiwyg/transaction"; import {openEditorTab} from "../../../menus/util"; import {copySubMenu} from "../../../menus/commonMenuItem"; -import {openCalcMenu, popTextCell} from "./cell"; +import {getTypeByCellElement, openCalcMenu, popTextCell} from "./cell"; import {getColIconByType, showColMenu} from "./col"; import {insertAttrViewBlockAnimation, updateHeader} from "./row"; import {emitOpenMenu} from "../../../plugin/EventBus"; @@ -70,7 +70,10 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle const gutterElement = hasClosestByClassName(event.target, "ariaLabel"); if (gutterElement && gutterElement.parentElement.classList.contains("av__gutters")) { - const rowElement = gutterElement.parentElement.parentElement; + const rowElement = hasClosestByClassName(gutterElement, "av__row"); + if (!rowElement) { + return + } if (gutterElement.dataset.action === "add") { const avID = blockElement.getAttribute("data-av-id"); const srcIDs = [Lute.NewNodeID()]; @@ -200,16 +203,24 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle } const cellElement = hasClosestByClassName(event.target, "av__cell"); - if (cellElement && !cellElement.parentElement.classList.contains("av__row--header")) { - const type = cellElement.parentElement.parentElement.firstElementChild.querySelector(`[data-col-id="${cellElement.getAttribute("data-col-id")}"]`).getAttribute("data-dtype") as TAVCol; + if (cellElement && !hasClosestByClassName(cellElement, "av__row--header")) { + const scrollElement = hasClosestByClassName(cellElement, "av__scroll") + if (!scrollElement) { + return + } + const rowElement = hasClosestByClassName(cellElement, "av__row"); + if (!rowElement) { + return; + } + const type = getTypeByCellElement(cellElement); if (type === "updated" || type === "created" || (type === "block" && !cellElement.getAttribute("data-detached"))) { - selectRow(cellElement.parentElement.querySelector(".av__firstcol"), "toggle"); + selectRow(rowElement.querySelector(".av__firstcol"), "toggle"); } else { - cellElement.parentElement.parentElement.querySelectorAll(".av__row--select").forEach(item => { + scrollElement.querySelectorAll(".av__row--select").forEach(item => { item.querySelector(".av__firstcol use").setAttribute("xlink:href", "#iconUncheck"); item.classList.remove("av__row--select"); }); - updateHeader(cellElement.parentElement); + updateHeader(rowElement); popTextCell(protyle, [cellElement]); } event.preventDefault(); @@ -307,7 +318,7 @@ export const avContextmenu = (protyle: IProtyle, rowElement: HTMLElement, positi updateHeader(blockElement.querySelector(".av__row")); } }); - if (rowIds.length === 1) { + if (rowIds.length === 1 && !rowElements[0].querySelector('[data-detached="true"]')) { menu.addSeparator(); openEditorTab(protyle.app, rowIds[0]); menu.addItem({ @@ -410,8 +421,7 @@ export const updateAVName = (protyle: IProtyle, blockElement: Element) => { }; export const updateAttrViewCellAnimation = (cellElement: HTMLElement) => { - cellElement.style.opacity = "0.38"; - cellElement.style.backgroundColor = "var(--b3-theme-surface-light)"; + cellElement.style.backgroundColor = "var(--b3-av-hover)"; }; export const removeAttrViewColAnimation = (blockElement: Element, id: string) => { diff --git a/app/src/protyle/render/av/asset.ts b/app/src/protyle/render/av/asset.ts index c697f7226..df9398b86 100644 --- a/app/src/protyle/render/av/asset.ts +++ b/app/src/protyle/render/av/asset.ts @@ -13,6 +13,7 @@ import {previewImage} from "../../preview/image"; import {genAVValueHTML} from "./blockAttr"; import {hideMessage, showMessage} from "../../../dialog/message"; import {fetchPost} from "../../../util/fetch"; +import {hasClosestByClassName} from "../../util/hasClosest"; export const bindAssetEvent = (options: { protyle: IProtyle, @@ -49,7 +50,7 @@ export const bindAssetEvent = (options: { export const getAssetHTML = (data: IAVTable, cellElements: HTMLElement[]) => { const cellId = cellElements[0].dataset.id; - const rowId = cellElements[0].parentElement.dataset.id; + const rowId = (hasClosestByClassName(cellElements[0], "av__row") as HTMLElement).dataset.id; let cellData: IAVCell; data.rows.find(row => { if (row.id === rowId) { @@ -112,7 +113,7 @@ export const updateAssetCell = (options: { removeContent?: string }) => { let cellIndex: number; - Array.from(options.cellElements[0].parentElement.querySelectorAll(".av__cell")).find((item: HTMLElement, index) => { + Array.from((hasClosestByClassName(options.cellElements[0], "av__row") as HTMLElement).querySelectorAll(".av__cell")).find((item: HTMLElement, index) => { if (item.dataset.id === options.cellElements[0].dataset.id) { cellIndex = index; return true; @@ -124,7 +125,7 @@ export const updateAssetCell = (options: { let newValue: IAVCellAssetValue[] = []; options.cellElements.forEach((item, elementIndex) => { let cellData: IAVCell; - const rowID = item.parentElement.dataset.id; + const rowID = (hasClosestByClassName(item, "av__row") as HTMLElement).dataset.id; options.data.view.rows.find(row => { if (row.id === rowID) { if (typeof cellIndex === "number") { diff --git a/app/src/protyle/render/av/blockAttr.ts b/app/src/protyle/render/av/blockAttr.ts index 394ea17ed..3ec224b26 100644 --- a/app/src/protyle/render/av/blockAttr.ts +++ b/app/src/protyle/render/av/blockAttr.ts @@ -90,7 +90,7 @@ export const renderAVAttribute = (element: HTMLElement, id: string, protyle?: IP ${table.avName || window.siyuan.languages.database} `; table.keyValues?.forEach(item => { - html += `
+ html += `
`; }); setTimeout(() => { - e.firstElementChild.outerHTML = `
+ e.firstElementChild.outerHTML = `
${tabHTML} @@ -199,10 +234,12 @@ ${cell.color ? `color:${cell.color};` : ""}">${text}
`;
${tableHTML}
- - ${window.siyuan.languages.addAttr} +
+ + ${window.siyuan.languages.addAttr} +
- +
`; @@ -223,7 +260,9 @@ ${cell.color ? `color:${cell.color};` : ""}">${text}
`; if (newCellElement) { newCellElement.classList.add("av__cell--select"); } - focusBlock(e); + if (!document.querySelector(".av__panel")) { + focusBlock(e); + } } if (cb) { cb(); @@ -270,7 +309,7 @@ export const refreshAV = (protyle: IProtyle, operation: IOperation, isUndo: bool avRender(item, protyle, () => { // https://github.com/siyuan-note/siyuan/issues/9599 if (!isUndo && operation.action === "insertAttrViewBlock" && operation.isDetached) { - popTextCell(protyle, [item.querySelector(`.av__row[data-id="${operation.srcIDs[0]}"] > .av__cell[data-detached="true"]`)], "block"); + popTextCell(protyle, [item.querySelector(`.av__row[data-id="${operation.srcIDs[0]}"] .av__cell[data-detached="true"]`)], "block"); } }); }); diff --git a/app/src/protyle/render/av/row.ts b/app/src/protyle/render/av/row.ts index 5a2646ba9..48d3e16b5 100644 --- a/app/src/protyle/render/av/row.ts +++ b/app/src/protyle/render/av/row.ts @@ -1,27 +1,36 @@ -import {hasClosestBlock} from "../../util/hasClosest"; +import {hasClosestBlock, hasClosestByClassName} from "../../util/hasClosest"; import {focusBlock} from "../../util/selection"; export const selectRow = (checkElement: Element, type: "toggle" | "select" | "unselect" | "unselectAll") => { - const rowElement = checkElement.parentElement; + const rowElement = hasClosestByClassName(checkElement, "av__row"); + if (!rowElement) { + return + } const useElement = checkElement.querySelector("use"); if (rowElement.classList.contains("av__row--header") || type === "unselectAll") { if ("#iconCheck" === useElement.getAttribute("xlink:href")) { rowElement.parentElement.querySelectorAll(".av__firstcol").forEach(item => { item.querySelector("use").setAttribute("xlink:href", "#iconUncheck"); - item.parentElement.classList.remove("av__row--select"); + const rowItemElement = hasClosestByClassName(item, "av__row"); + if (rowItemElement) { + rowItemElement.classList.remove("av__row--select"); + } }); } else { rowElement.parentElement.querySelectorAll(".av__firstcol").forEach(item => { item.querySelector("use").setAttribute("xlink:href", "#iconCheck"); - item.parentElement.classList.add("av__row--select"); + const rowItemElement = hasClosestByClassName(item, "av__row"); + if (rowItemElement) { + rowItemElement.classList.add("av__row--select"); + } }); } } else { if (type === "select" || (useElement.getAttribute("xlink:href") === "#iconUncheck" && type === "toggle")) { - checkElement.parentElement.classList.add("av__row--select"); + rowElement.classList.add("av__row--select"); useElement.setAttribute("xlink:href", "#iconCheck"); } else if (type === "unselect" || (useElement.getAttribute("xlink:href") === "#iconCheck" && type === "toggle")) { - checkElement.parentElement.classList.remove("av__row--select"); + rowElement.classList.remove("av__row--select"); useElement.setAttribute("xlink:href", "#iconUncheck"); } } @@ -60,15 +69,21 @@ export const updateHeader = (rowElement: HTMLElement) => { export const insertAttrViewBlockAnimation = (blockElement: Element, size: number, previousId: string, avId?: string) => { const previousElement = blockElement.querySelector(`.av__row[data-id="${previousId}"]`) || blockElement.querySelector(".av__row--header"); - let colHTML = ""; - previousElement.querySelectorAll(".av__cell").forEach((item: HTMLElement) => { + let colHTML = '
'; + const pinIndex = previousElement.querySelectorAll(".av__colsticky .av__cell").length - 1; + if (pinIndex > -1) { + colHTML = `
`; + } + previousElement.querySelectorAll(".av__cell").forEach((item: HTMLElement, index) => { colHTML += `
`; + if (pinIndex === index) { + colHTML += `
`; + } }); let html = ""; new Array(size).fill(1).forEach(() => { html += `
-
${colHTML}
`; }); diff --git a/app/src/protyle/render/av/select.ts b/app/src/protyle/render/av/select.ts index f2eb5993f..845eda375 100644 --- a/app/src/protyle/render/av/select.ts +++ b/app/src/protyle/render/av/select.ts @@ -54,7 +54,7 @@ export const removeCellOption = (protyle: IProtyle, data: IAV, cellElements: HTM const undoOperations: IOperation[] = []; let newData: IAVCellSelectValue[]; cellElements.forEach((item, elementIndex) => { - const rowID = item.parentElement.dataset.id; + const rowID = (hasClosestByClassName(item, "av__row") as HTMLElement).dataset.id; const cellId = item.dataset.id; let cellData: IAVCell; data.view.rows.find(row => { @@ -157,7 +157,7 @@ export const setColOption = (protyle: IProtyle, data: IAV, target: HTMLElement, } else { cellElements.forEach((cellElement: HTMLMediaElement) => { data.view.rows.find(row => { - if (row.id === cellElement.parentElement.dataset.id) { + if (row.id === (hasClosestByClassName(cellElement, "av__row") as HTMLElement).dataset.id) { row.cells.find(cell => { if (cell.id === cellElement.dataset.id) { cell.value.mSelect.find((item) => { @@ -235,7 +235,7 @@ export const setColOption = (protyle: IProtyle, data: IAV, target: HTMLElement, } else { cellElements.forEach((cellElement: HTMLElement) => { data.view.rows.find(row => { - if (row.id === cellElement.parentElement.dataset.id) { + if (row.id === (hasClosestByClassName(cellElement, "av__row") as HTMLElement).dataset.id) { row.cells.find(cell => { if (cell.id === cellElement.dataset.id) { cell.value.mSelect.find((item, index) => { @@ -314,7 +314,7 @@ export const setColOption = (protyle: IProtyle, data: IAV, target: HTMLElement, } else { cellElements.forEach((cellElement: HTMLElement) => { data.view.rows.find(row => { - if (row.id === cellElement.parentElement.dataset.id) { + if (row.id === (hasClosestByClassName(cellElement, "av__row") as HTMLElement).dataset.id) { row.cells.find(cell => { if (cell.id === cellElement.dataset.id) { cell.value.mSelect.find((item) => { @@ -394,8 +394,6 @@ export const bindSelectEvent = (protyle: IProtyle, data: IAV, menuElement: HTMLE addColOptionOrCell(protyle, data, cellElements, currentElement, menuElement); } else if (event.key === "Backspace" && inputElement.value === "") { removeCellOption(protyle, data, cellElements, inputElement.previousElementSibling as HTMLElement); - } else if (event.key === "Escape") { - menuElement.parentElement.remove(); } }); }; @@ -413,14 +411,18 @@ export const addColOptionOrCell = (protyle: IProtyle, data: IAV, cellElements: H return; } - const colId = cellElements[0].dataset.colId; + const rowElement = hasClosestByClassName(cellElements[0], "av__row"); + if (!rowElement) { + return; + } let cellIndex: number; - Array.from(cellElements[0].parentElement.querySelectorAll(".av__cell")).find((item: HTMLElement, index) => { + Array.from(rowElement.querySelectorAll(".av__cell")).find((item: HTMLElement, index) => { if (item.dataset.id === cellElements[0].dataset.id) { cellIndex = index; return true; } }); + const colId = cellElements[0].dataset.colId; let colData: IAVColumn; data.view.columns.find((item: IAVColumn) => { if (item.id === colId) { @@ -436,8 +438,12 @@ export const addColOptionOrCell = (protyle: IProtyle, data: IAV, cellElements: H const cellUndoOperations: IOperation[] = []; let newValue: IAVCellSelectValue[]; cellElements.forEach((item, index) => { + const itemRowElement = hasClosestByClassName(item, "av__row"); + if (!itemRowElement) { + return; + } let cellData: IAVCell; - const rowID = item.parentElement.dataset.id; + const rowID = itemRowElement.dataset.id; data.view.rows.find(row => { if (row.id === rowID) { if (typeof cellIndex === "number") { @@ -553,7 +559,8 @@ export const getSelectHTML = (data: IAVTable, cellElements: HTMLElement[]) => { let allUniqueOptions: IAVCellSelectValue[] = []; data.rows.find(row => { - if (cellElements[0].parentElement.dataset.id === row.id) { + const rowElement = hasClosestByClassName(cellElements[0], "av__row"); + if (rowElement && rowElement.dataset.id === row.id) { row.cells.find(cell => { if (cell.id === cellElements[0].dataset.id) { if (cell.value && cell.value.mSelect) { diff --git a/app/src/protyle/scroll/event.ts b/app/src/protyle/scroll/event.ts index f83586fdb..24d1a1f8b 100644 --- a/app/src/protyle/scroll/event.ts +++ b/app/src/protyle/scroll/event.ts @@ -27,7 +27,7 @@ export const scrollEvent = (protyle: IProtyle, element: HTMLElement) => { const scrollRect = item.querySelector(".av__scroll").getBoundingClientRect() const headerElement = item.querySelector(".av__row--header") as HTMLElement; if (headerElement) { - const distance = elementRect.top - scrollRect.top; + const distance = Math.floor(elementRect.top - scrollRect.top); if (distance > 0 && distance < scrollRect.height) { headerElement.style.transform = `translateY(${distance}px)`; } else { @@ -37,7 +37,7 @@ export const scrollEvent = (protyle: IProtyle, element: HTMLElement) => { const footerElement = item.querySelector(".av__row--footer") as HTMLElement; if (footerElement) { if (footerElement.querySelector(".av__calc--ashow")) { - const distance = elementRect.bottom - scrollRect.bottom; + const distance = Math.floor(elementRect.bottom - footerElement.parentElement.getBoundingClientRect().bottom); if (distance < 0 && -distance < scrollRect.height) { footerElement.style.transform = `translateY(${distance}px)`; } else { diff --git a/app/src/protyle/toolbar/Font.ts b/app/src/protyle/toolbar/Font.ts index 4bf8df442..f1ad62cf3 100644 --- a/app/src/protyle/toolbar/Font.ts +++ b/app/src/protyle/toolbar/Font.ts @@ -216,10 +216,16 @@ export const fontEvent = (protyle: IProtyle, nodeElements: Element[], type?: str e.style.textShadow = ""; e.style.backgroundColor = ""; e.style.fontSize = ""; + if (e.classList.contains("av")) { + e.querySelector(".av__container").setAttribute("style", "--av-background:--b3-theme-background"); + } } else if (type === "style1") { const colorList = color.split(Constants.ZWSP); e.style.backgroundColor = colorList[0]; e.style.color = colorList[1]; + if (e.classList.contains("av")) { + e.querySelector(".av__container").setAttribute("style", `--av-background:${colorList[0]}`); + } } else if (type === "style2") { e.style.webkitTextStroke = "0.2px var(--b3-theme-on-background)"; e.style.webkitTextFillColor = "transparent"; @@ -229,6 +235,9 @@ export const fontEvent = (protyle: IProtyle, nodeElements: Element[], type?: str e.style.color = color; } else if (type === "backgroundColor") { e.style.backgroundColor = color; + if (e.classList.contains("av")) { + e.querySelector(".av__container").setAttribute("style", `--av-background:${color}`); + } } else if (type === "fontSize") { e.style.fontSize = color; } diff --git a/app/src/protyle/util/editorCommonEvent.ts b/app/src/protyle/util/editorCommonEvent.ts index 32b3ca267..706890f87 100644 --- a/app/src/protyle/util/editorCommonEvent.ts +++ b/app/src/protyle/util/editorCommonEvent.ts @@ -852,15 +852,39 @@ export const dropEvent = (protyle: IProtyle, editorElement: HTMLElement) => { const blockElement = hasClosestBlock(targetElement); if (blockElement) { const avID = blockElement.getAttribute("data-av-id"); + let previousID = ""; + if (targetClass.includes("dragover__left")) { + if (targetElement.previousElementSibling) { + if (targetElement.previousElementSibling.classList.contains("av__colsticky")) { + previousID = targetElement.previousElementSibling.lastElementChild.getAttribute("data-col-id") + } else { + previousID = targetElement.previousElementSibling.getAttribute("data-col-id") + } + } + } else { + previousID = targetElement.getAttribute("data-col-id") + } + let oldPreviousID = ""; + const rowElement = hasClosestByClassName(targetElement, "av__row"); + if (rowElement) { + const oldPreviousElement = rowElement.querySelector(`[data-col-id="${gutterTypes[2]}"`)?.previousElementSibling + if (oldPreviousElement) { + if (oldPreviousElement.classList.contains("av__colsticky")) { + oldPreviousID = oldPreviousElement.lastElementChild.getAttribute("data-col-id") + } else { + oldPreviousID = oldPreviousElement.getAttribute("data-col-id") + } + } + } transaction(protyle, [{ action: "sortAttrViewCol", avID, - previousID: (targetClass.includes("dragover__left") ? targetElement.previousElementSibling?.getAttribute("data-col-id") : targetElement.getAttribute("data-col-id")) || "", + previousID, id: gutterTypes[2], }], [{ action: "sortAttrViewCol", avID, - previousID: targetElement.parentElement.querySelector(`[data-col-id="${gutterTypes[2]}"`).previousElementSibling?.getAttribute("data-col-id") || "", + previousID: oldPreviousID, id: gutterTypes[2], }]); } @@ -1111,8 +1135,14 @@ export const dropEvent = (protyle: IProtyle, editorElement: HTMLElement) => { if (gutterType && gutterType.startsWith(`${Constants.SIYUAN_DROP_GUTTER}NodeAttributeView${Constants.ZWSP}Col${Constants.ZWSP}`.toLowerCase())) { // 表头只能拖拽到当前 av 的表头中 targetElement = hasClosestByClassName(event.target, "av__cell"); - if (targetElement && !targetElement.parentElement.isSameNode(window.siyuan.dragElement.parentElement)) { - targetElement = false; + if (targetElement) { + const targetRowElement = hasClosestByClassName(targetElement, "av__row--header") + const dragRowElement = hasClosestByClassName(window.siyuan.dragElement, "av__row--header") + if (!targetRowElement || !dragRowElement || + (targetRowElement && dragRowElement && !targetRowElement.isSameNode(dragRowElement)) + ) { + targetElement = false; + } } } else if (targetElement && gutterType && gutterType.startsWith(`${Constants.SIYUAN_DROP_GUTTER}NodeAttributeView${Constants.ZWSP}Row${Constants.ZWSP}`.toLowerCase())) { // 行只能拖拽当前 av 中 diff --git a/app/src/protyle/wysiwyg/index.ts b/app/src/protyle/wysiwyg/index.ts index 8c5c41386..631d65acd 100644 --- a/app/src/protyle/wysiwyg/index.ts +++ b/app/src/protyle/wysiwyg/index.ts @@ -384,9 +384,12 @@ export class WYSIWYG { let newWidth: string; documentSelf.onmousemove = (moveEvent: MouseEvent) => { newWidth = Math.max(oldWidth + (moveEvent.clientX - event.clientX), 58) + "px"; - dragElement.parentElement.parentElement.querySelectorAll(".av__row, .av__row--footer").forEach(item => { - (item.querySelector(`[data-col-id="${dragColId}"]`) as HTMLElement).style.width = newWidth; - }); + const scrollElement = hasClosestByClassName(dragElement, "av__scroll") + if (scrollElement) { + scrollElement.querySelectorAll(".av__row, .av__row--footer").forEach(item => { + (item.querySelector(`[data-col-id="${dragColId}"]`) as HTMLElement).style.width = newWidth; + }); + } }; documentSelf.onmouseup = () => { diff --git a/app/src/protyle/wysiwyg/transaction.ts b/app/src/protyle/wysiwyg/transaction.ts index dfdb1ffa1..bbdfd0304 100644 --- a/app/src/protyle/wysiwyg/transaction.ts +++ b/app/src/protyle/wysiwyg/transaction.ts @@ -711,7 +711,7 @@ export const onTransaction = (protyle: IProtyle, operation: IOperation, isUndo: "updateAttrViewColOption", "updateAttrViewCell", "sortAttrViewRow", "sortAttrViewCol", "setAttrViewColHidden", "setAttrViewColWrap", "setAttrViewColWidth", "removeAttrViewColOption", "setAttrViewName", "setAttrViewFilters", "setAttrViewSorts", "setAttrViewColCalc", "removeAttrViewCol", "updateAttrViewColNumberFormat", "removeAttrViewBlock", - "replaceAttrViewBlock", "updateAttrViewColTemplate", "setAttrViewColIcon"].includes(operation.action)) { + "replaceAttrViewBlock", "updateAttrViewColTemplate", "setAttrViewColIcon", "setAttrViewColPin"].includes(operation.action)) { refreshAV(protyle, operation, isUndo); } else if (operation.action === "doUpdateUpdated") { updateElements.forEach(item => { diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index 62d8f31bf..7a8f16300 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -27,6 +27,7 @@ type TOperation = | "updateAttrViewColTemplate" | "sortAttrViewRow" | "sortAttrViewCol" + | "setAttrViewColPin" | "setAttrViewColHidden" | "setAttrViewColWrap" | "setAttrViewColWidth" @@ -1029,11 +1030,12 @@ interface IAVSort { } interface IAVColumn { - width: number, + width: string, icon: string, id: string, name: string, wrap: boolean, + pin: boolean, hidden: boolean, type: TAVCol, numberFormat: string,