diff --git a/app/appearance/langs/en_US.json b/app/appearance/langs/en_US.json index 37a82141e..66dc9ea8a 100644 --- a/app/appearance/langs/en_US.json +++ b/app/appearance/langs/en_US.json @@ -1,4 +1,7 @@ { + "hide": "Hide", + "wrap": "Wrap column", + "edit": "Edit", "incompatiblePluginTip": "This plugin is not supported on the current terminal", "incompatible": "Incompatible", "trust": "Trust", diff --git a/app/appearance/langs/es_ES.json b/app/appearance/langs/es_ES.json index 2ce353eab..4516e9e9f 100644 --- a/app/appearance/langs/es_ES.json +++ b/app/appearance/langs/es_ES.json @@ -1,4 +1,7 @@ { + "hide": "Ocultar", + "wrap": "Columna de ajuste", + "edit": "Editar", "incompatiblePluginTip": "Este complemento no es compatible con el terminal actual", "incompatible": "Incompatible", "trust": "Confiar", diff --git a/app/appearance/langs/fr_FR.json b/app/appearance/langs/fr_FR.json index 6980d2fa8..b5018f804 100644 --- a/app/appearance/langs/fr_FR.json +++ b/app/appearance/langs/fr_FR.json @@ -1,4 +1,7 @@ { + "hide": "Masquer", + "wrap": "Reboucler la colonne", + "edit": "Modifier", "incompatiblePluginTip": "Ce plugin n'est pas supporté sur le terminal actuel", "incompatible": "Incompatible", "trust": "Confiance", diff --git a/app/appearance/langs/zh_CHT.json b/app/appearance/langs/zh_CHT.json index 9c15eb48d..37f0ba729 100644 --- a/app/appearance/langs/zh_CHT.json +++ b/app/appearance/langs/zh_CHT.json @@ -1,4 +1,7 @@ { + "hide": "隱藏", + "wrap": "換行", + "edit": "編輯", "incompatiblePluginTip": "該插件不支持在當前終端上使用", "incompatible": "不兼容", "trust": "信任", diff --git a/app/appearance/langs/zh_CN.json b/app/appearance/langs/zh_CN.json index fbf15a43a..d360651ef 100644 --- a/app/appearance/langs/zh_CN.json +++ b/app/appearance/langs/zh_CN.json @@ -1,4 +1,7 @@ { + "hide": "隐藏", + "wrap": "换行", + "edit": "编辑", "incompatiblePluginTip": "该插件不支持在当前终端上使用", "incompatible": "不兼容", "trust": "信任", diff --git a/app/src/assets/scss/protyle/_wysiwyg.scss b/app/src/assets/scss/protyle/_wysiwyg.scss index 4302e4ebe..d484153c4 100644 --- a/app/src/assets/scss/protyle/_wysiwyg.scss +++ b/app/src/assets/scss/protyle/_wysiwyg.scss @@ -42,6 +42,23 @@ &__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 { diff --git a/app/src/mobile/util/MobileBackFoward.ts b/app/src/mobile/util/MobileBackFoward.ts index fc5a7c909..441f18447 100644 --- a/app/src/mobile/util/MobileBackFoward.ts +++ b/app/src/mobile/util/MobileBackFoward.ts @@ -11,7 +11,7 @@ import {setStorageVal} from "../../protyle/util/compatibility"; import {closePanel} from "./closePanel"; import {showMessage} from "../../dialog/message"; import {getCurrentEditor} from "../editor"; -import {avRender} from "../../protyle/render/av"; +import {avRender} from "../../protyle/render/av/render"; const forwardStack: IBackStack[] = []; diff --git a/app/src/protyle/gutter/index.ts b/app/src/protyle/gutter/index.ts index c2f260d80..a3091c599 100644 --- a/app/src/protyle/gutter/index.ts +++ b/app/src/protyle/gutter/index.ts @@ -40,7 +40,7 @@ import {activeBlur} from "../../mobile/util/keyboardToolbar"; import {hideTooltip} from "../../dialog/tooltip"; import {appearanceMenu} from "../toolbar/Font"; import {setPosition} from "../../util/setPosition"; -import {avRender} from "../render/av"; +import {avRender} from "../render/av/render"; export class Gutter { public element: HTMLElement; diff --git a/app/src/protyle/hint/extend.ts b/app/src/protyle/hint/extend.ts index e7ab3cdb2..f5ac11327 100644 --- a/app/src/protyle/hint/extend.ts +++ b/app/src/protyle/hint/extend.ts @@ -19,7 +19,7 @@ import {zoomOut} from "../../menus/protyle"; import {hideElements} from "../ui/hideElements"; import {genAssetHTML} from "../../asset/renderAssets"; import {unicode2Emoji} from "../../emoji"; -import {avRender} from "../render/av"; +import {avRender} from "../render/av/render"; export const hintSlash = (key: string, protyle: IProtyle) => { const allList: IHintData[] = [{ diff --git a/app/src/protyle/hint/index.ts b/app/src/protyle/hint/index.ts index 1c72ffde2..ac38cb26d 100644 --- a/app/src/protyle/hint/index.ts +++ b/app/src/protyle/hint/index.ts @@ -32,7 +32,7 @@ import {processRender} from "../util/processCode"; import {AIChat} from "../../ai/chat"; import {isMobile} from "../../util/functions"; import {isCtrl} from "../util/compatibility"; -import {avRender} from "../render/av"; +import {avRender} from "../render/av/render"; export class Hint { public timeId: number; diff --git a/app/src/protyle/method.ts b/app/src/protyle/method.ts index 77c954322..899a9d5da 100644 --- a/app/src/protyle/method.ts +++ b/app/src/protyle/method.ts @@ -7,7 +7,7 @@ import { chartRender } from "./render/chartRender"; import { abcRender } from "./render/abcRender"; import { mindmapRender } from "./render/mindmapRender"; import { plantumlRender } from "./render/plantumlRender"; -import { avRender } from "./render/av"; +import { avRender } from "./render/av/render"; import "../assets/scss/export.scss"; class Protyle { diff --git a/app/src/protyle/preview/index.ts b/app/src/protyle/preview/index.ts index b12447ce5..a52c99bb1 100644 --- a/app/src/protyle/preview/index.ts +++ b/app/src/protyle/preview/index.ts @@ -17,7 +17,7 @@ import {fetchPost} from "../../util/fetch"; import {processRender} from "../util/processCode"; import {highlightRender} from "../render/highlightRender"; import {speechRender} from "../render/speechRender"; -import {avRender} from "../render/av"; +import {avRender} from "../render/av/render"; export class Preview { public element: HTMLElement; diff --git a/app/src/protyle/render/av/action.ts b/app/src/protyle/render/av/action.ts index 8ea97fbb6..06ae229e9 100644 --- a/app/src/protyle/render/av/action.ts +++ b/app/src/protyle/render/av/action.ts @@ -1,6 +1,7 @@ import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName} from "../../util/hasClosest"; import {transaction} from "../../wysiwyg/transaction"; import {Menu} from "../../../plugin/API"; +import {getIconByType} from "./render"; export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLElement }) => { const blockElement = hasClosestBlock(event.target) @@ -23,13 +24,13 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle id, parentID: blockElement.getAttribute("data-av-type"), }]); - } }) const addRect = addElement.getBoundingClientRect() menu.open({ x: addRect.left, - y: addRect.bottom + y: addRect.bottom, + h: addRect.height }) event.preventDefault(); event.stopPropagation(); @@ -37,6 +38,84 @@ 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") + const menu = new Menu("av-header-cell") + menu.addItem({ + icon: getIconByType(type), + label: ``, + bind() { + + } + }) + if (type !== "block") { + menu.addItem({ + icon: "iconEdit", + label: window.siyuan.languages.edit, + click() { + + } + }) + } + menu.addSeparator() + menu.addItem({ + icon: "iconUp", + label: window.siyuan.languages.fileNameNatASC, + click() { + + } + }) + menu.addItem({ + icon: "iconDown", + label: window.siyuan.languages.fileNameNatDESC, + click() { + + } + }) + menu.addItem({ + icon: "iconFilter", + label: window.siyuan.languages.filter, + click() { + + } + }) + menu.addSeparator() + if (type !== "block") { + menu.addItem({ + icon: "iconEyeoff", + label: window.siyuan.languages.hide, + click() { + + } + }) + menu.addItem({ + icon: "iconCopy", + label: window.siyuan.languages.duplicate, + click() { + + } + }) + menu.addItem({ + icon: "iconTrashcan", + label: window.siyuan.languages.delete, + click() { + + } + }) + menu.addSeparator() + } + menu.addItem({ + label: `
${window.siyuan.languages.wrap} +
`, + click() { + + } + }) + const cellRect = cellElement.getBoundingClientRect() + menu.open({ + x: cellRect.left, + y: cellRect.bottom, + h: cellRect.height + }) event.preventDefault(); event.stopPropagation(); return true diff --git a/app/src/protyle/render/av/index.ts b/app/src/protyle/render/av/render.ts similarity index 77% rename from app/src/protyle/render/av/index.ts rename to app/src/protyle/render/av/render.ts index 22bb6822d..c5aa763ea 100644 --- a/app/src/protyle/render/av/index.ts +++ b/app/src/protyle/render/av/render.ts @@ -1,5 +1,14 @@ import {fetchPost} from "../../../util/fetch"; +export const getIconByType = (type: string) => { + switch (type) { + case "text": + return "iconAlignLeft"; + case "block": + return "iconParagraph"; + } +} + export const avRender = (element: Element) => { let avElements: Element[] = []; if (element.getAttribute("data-type") === "NodeAttributeView") { @@ -12,18 +21,23 @@ export const avRender = (element: Element) => { return; } if (avElements.length > 0) { - avElements.forEach((e: HTMLDivElement) => { + avElements.forEach((e: HTMLElement) => { if (e.getAttribute("data-render") === "true") { return; } fetchPost("/api/av/renderAttributeView", {id: e.getAttribute("data-av-id")}, (response) => { const data = response.data.av; - + this.data = data; // header - let tableHTML = '
'; + let tableHTML = '
'; data.columns.forEach((column: IAVColumn) => { - tableHTML += ` -
${column.name}
` + if (column.hidden) { + return; + } + tableHTML += `
+ + ${column.name} +
` }); tableHTML += `
@@ -55,18 +69,19 @@ export const avRender = (element: Element) => {
-
+
${tableHTML}
${window.siyuan.languages.addAttr}
+
`; e.setAttribute("data-render", "true"); - }) + }); }); } }; diff --git a/app/src/protyle/render/blockRender.ts b/app/src/protyle/render/blockRender.ts index 05e437167..e8c2d7b98 100644 --- a/app/src/protyle/render/blockRender.ts +++ b/app/src/protyle/render/blockRender.ts @@ -4,7 +4,7 @@ import {processRender} from "../util/processCode"; import {highlightRender} from "./highlightRender"; import {Constants} from "../../constants"; import {genBreadcrumb} from "../wysiwyg/renderBacklink"; -import {avRender} from "./av"; +import {avRender} from "./av/render"; export const blockRender = (protyle: IProtyle, element: Element, top?: number) => { let blockElements: Element[] = []; diff --git a/app/src/protyle/scroll/event.ts b/app/src/protyle/scroll/event.ts index c4182efce..8bb89cb25 100644 --- a/app/src/protyle/scroll/event.ts +++ b/app/src/protyle/scroll/event.ts @@ -26,7 +26,7 @@ export const scrollEvent = (protyle: IProtyle, element: HTMLElement) => { protyle.wysiwyg.element.querySelectorAll(".av").forEach((item: HTMLElement) => { if (item.parentElement.classList.contains("protyle-wysiwyg")) { - const headerTop = item.offsetTop - 30 + 56 + const headerTop = item.offsetTop - 30 + 56; // 30 - 面包屑, 56 - tab+title const headerElement = item.querySelector(".av__row--header") as HTMLElement if (headerElement) { if (headerTop < element.scrollTop && headerTop + headerElement.parentElement.clientHeight > element.scrollTop) { @@ -35,6 +35,16 @@ export const scrollEvent = (protyle: IProtyle, element: HTMLElement) => { headerElement.style.transform = ""; } } + const footerElement = item.querySelector(".av__row--footer") as HTMLElement + if (footerElement) { + const footerBottom = headerTop + footerElement.parentElement.clientHeight + const scrollBottom = element.scrollTop + element.clientHeight; + if (headerTop + 42 + 36 * 2 < scrollBottom && footerBottom > scrollBottom) { + footerElement.style.transform = `translateY(${scrollBottom - footerBottom}px)`; + } else { + footerElement.style.transform = ""; + } + } } }); diff --git a/app/src/protyle/util/onGet.ts b/app/src/protyle/util/onGet.ts index 6e15accfd..97b739e2c 100644 --- a/app/src/protyle/util/onGet.ts +++ b/app/src/protyle/util/onGet.ts @@ -16,7 +16,7 @@ import {removeLoading} from "../ui/initUI"; import {isMobile} from "../../util/functions"; import {foldPassiveType} from "../wysiwyg/renderBacklink"; import {showMessage} from "../../dialog/message"; -import {avRender} from "../render/av"; +import {avRender} from "../render/av/render"; export const onGet = (options: { data: IWebSocketData, diff --git a/app/src/protyle/util/paste.ts b/app/src/protyle/util/paste.ts index 08534845d..6778b1723 100644 --- a/app/src/protyle/util/paste.ts +++ b/app/src/protyle/util/paste.ts @@ -14,7 +14,7 @@ import {isDynamicRef, isFileAnnotation} from "../../util/functions"; import {insertHTML} from "./insertHTML"; import {scrollCenter} from "../../util/highlightById"; import {hideElements} from "../ui/hideElements"; -import {avRender} from "../render/av"; +import {avRender} from "../render/av/render"; const filterClipboardHint = (protyle: IProtyle, textPlain: string) => { let needRender = true; diff --git a/app/src/protyle/wysiwyg/renderBacklink.ts b/app/src/protyle/wysiwyg/renderBacklink.ts index 9f9bbf058..70f740717 100644 --- a/app/src/protyle/wysiwyg/renderBacklink.ts +++ b/app/src/protyle/wysiwyg/renderBacklink.ts @@ -6,7 +6,7 @@ import {processRender} from "../util/processCode"; import {highlightRender} from "../render/highlightRender"; import {blockRender} from "../render/blockRender"; import {disabledForeverProtyle, disabledProtyle} from "../util/onGet"; -import {avRender} from "../render/av"; +import {avRender} from "../render/av/render"; export const renderBacklink = (protyle: IProtyle, backlinkData: { blockPaths: IBreadcrumb[], diff --git a/app/src/protyle/wysiwyg/transaction.ts b/app/src/protyle/wysiwyg/transaction.ts index 711d6b2f8..ec0d0d549 100644 --- a/app/src/protyle/wysiwyg/transaction.ts +++ b/app/src/protyle/wysiwyg/transaction.ts @@ -17,7 +17,7 @@ import {hideElements} from "../ui/hideElements"; import {reloadProtyle} from "../util/reload"; import {countBlockWord} from "../../layout/status"; import {needSubscribe} from "../../util/needSubscribe"; -import {avRender} from "../render/av"; +import {avRender} from "../render/av/render"; const removeTopElement = (updateElement: Element, protyle: IProtyle) => { // 移动到其他文档中,该块需移除 diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index 699c8b369..f9893a2d7 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -26,6 +26,7 @@ type TBazaarType = "templates" | "icons" | "widgets" | "themes" | "plugins" type TCardType = "doc" | "notebook" | "all" type TEventBus = "ws-main" | "click-blockicon" | "click-editorcontent" | "click-pdf" | "click-editortitleicon" | "open-noneditableblock" | "loaded-protyle" +type TAVCol = "text" | "date" | "number" | "relation" | "rollup" | "select" | "block" declare module "blueimp-md5" @@ -282,7 +283,7 @@ interface IOperation { nextID?: string // insert 专享 srcIDs?: string[] // insertAttrViewBlock 专享 name?: string // addAttrViewCol 专享 - type?: "text" | "date" | "number" | "relation" | "rollup" | "select" // addAttrViewCol 专享 + type?: TAVCol // addAttrViewCol 专享 deckID?: string // add/removeFlashcards 专享 blockIDs?: string[] // add/removeFlashcards 专享 } @@ -810,7 +811,8 @@ interface IAVColumn { id: string, name: string, wrap: boolean, - type: string, + hidden: boolean, + type: TAVCol, } interface IAVRow {