mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-18 15:40:12 +01:00
This commit is contained in:
parent
b1a00c6ebd
commit
a0b238075d
8 changed files with 174 additions and 7 deletions
|
|
@ -56,7 +56,7 @@
|
||||||
<svg>
|
<svg>
|
||||||
<use xlink:href="#iconBoard"></use>
|
<use xlink:href="#iconBoard"></use>
|
||||||
</svg>
|
</svg>
|
||||||
<del>iconBoard</del>
|
iconBoard
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<svg>
|
<svg>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
|
"useBackground": "填充列背景颜色",
|
||||||
"print": "打印",
|
"print": "打印",
|
||||||
"clickArrow": "点击箭头",
|
"clickArrow": "点击箭头",
|
||||||
"foldAll": "全部折叠",
|
"foldAll": "全部折叠",
|
||||||
|
|
|
||||||
|
|
@ -972,6 +972,25 @@
|
||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__kanban {
|
||||||
|
overflow: auto;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 0 1px 16px;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
&-group {
|
||||||
|
width: 260px;
|
||||||
|
|
||||||
|
&--small {
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--big {
|
||||||
|
width: 320px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img.av__cellassetimg {
|
img.av__cellassetimg {
|
||||||
|
|
|
||||||
|
|
@ -368,3 +368,105 @@ export const renderGallery = async (options: {
|
||||||
options.blockElement.querySelector(".av__gallery").classList.add("av__gallery--top");
|
options.blockElement.querySelector(".av__gallery").classList.add("av__gallery--top");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const renderKanban = async (options: {
|
||||||
|
blockElement: HTMLElement,
|
||||||
|
protyle: IProtyle,
|
||||||
|
cb?: (data: IAV) => void,
|
||||||
|
renderAll: boolean,
|
||||||
|
data?: IAV,
|
||||||
|
}) => {
|
||||||
|
const searchInputElement = options.blockElement.querySelector('[data-type="av-search"]') as HTMLInputElement;
|
||||||
|
const editIds: IIds[] = [];
|
||||||
|
options.blockElement.querySelectorAll(".av__gallery-fields--edit").forEach(item => {
|
||||||
|
editIds.push({
|
||||||
|
groupId: (hasClosestByClassName(item, "av__body") as HTMLElement).dataset.groupId || "",
|
||||||
|
fieldId: item.parentElement.getAttribute("data-id"),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const selectItemIds: IIds[] = [];
|
||||||
|
options.blockElement.querySelectorAll(".av__gallery-item--select").forEach(galleryItem => {
|
||||||
|
const fieldId = galleryItem.getAttribute("data-id");
|
||||||
|
if (fieldId) {
|
||||||
|
selectItemIds.push({
|
||||||
|
groupId: (hasClosestByClassName(galleryItem, "av__body") as HTMLElement).dataset.groupId || "",
|
||||||
|
fieldId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const pageSizes: { [key: string]: string } = {};
|
||||||
|
options.blockElement.querySelectorAll(".av__body").forEach((item: HTMLElement) => {
|
||||||
|
pageSizes[item.dataset.groupId || "unGroup"] = item.dataset.pageSize;
|
||||||
|
});
|
||||||
|
const resetData = {
|
||||||
|
isSearching: searchInputElement && document.activeElement === searchInputElement,
|
||||||
|
query: searchInputElement?.value || "",
|
||||||
|
alignSelf: options.blockElement.style.alignSelf,
|
||||||
|
oldOffset: options.protyle.contentElement.scrollTop,
|
||||||
|
editIds,
|
||||||
|
selectItemIds,
|
||||||
|
pageSizes,
|
||||||
|
};
|
||||||
|
if (options.blockElement.firstElementChild.innerHTML === "") {
|
||||||
|
options.blockElement.style.alignSelf = "";
|
||||||
|
options.blockElement.firstElementChild.outerHTML = `<div class="av__kanban fn__flex">
|
||||||
|
<span style="width: 260px;height: 178px;" class="av__pulse"></span>
|
||||||
|
<span style="width: 260px;height: 178px;" class="av__pulse"></span>
|
||||||
|
<span style="width: 260px;height: 178px;" class="av__pulse"></span>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
const created = options.protyle.options.history?.created;
|
||||||
|
const snapshot = options.protyle.options.history?.snapshot;
|
||||||
|
|
||||||
|
let data: IAV = options.data;
|
||||||
|
if (!data) {
|
||||||
|
const avPageSize = getPageSize(options.blockElement);
|
||||||
|
const response = await fetchSyncPost(created ? "/api/av/renderHistoryAttributeView" : (snapshot ? "/api/av/renderSnapshotAttributeView" : "/api/av/renderAttributeView"), {
|
||||||
|
id: options.blockElement.getAttribute("data-av-id"),
|
||||||
|
created,
|
||||||
|
snapshot,
|
||||||
|
pageSize: avPageSize.unGroupPageSize,
|
||||||
|
groupPaging: avPageSize.groupPageSize,
|
||||||
|
viewID: options.blockElement.getAttribute(Constants.CUSTOM_SY_AV_VIEW) || "",
|
||||||
|
query: resetData.query.trim()
|
||||||
|
});
|
||||||
|
data = response.data;
|
||||||
|
}
|
||||||
|
if (data.viewType === "table") {
|
||||||
|
options.blockElement.setAttribute("data-av-type", "table");
|
||||||
|
avRender(options.blockElement, options.protyle, options.cb, options.renderAll);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const view: IAVGallery = data.view as IAVGallery;
|
||||||
|
let bodyHTML = ""
|
||||||
|
view.groups.forEach((group: IAVGallery) => {
|
||||||
|
if (group.groupHidden === 0) {
|
||||||
|
bodyHTML += `<div class="av__kanban-group">
|
||||||
|
${getGroupTitleHTML(group, group.cards.length)}
|
||||||
|
<div data-group-id="${group.id}" data-page-size="${group.pageSize}" data-dtype="${group.groupKey.type}" data-content="${Lute.EscapeHTMLStr(group.groupValue.text?.content)}" class="av__body${group.groupFolded ? " fn__none" : ""}">${getGalleryHTML(group)}</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (options.renderAll) {
|
||||||
|
options.blockElement.firstElementChild.outerHTML = `<div class="av__container fn__block">
|
||||||
|
${genTabHeaderHTML(data, resetData.isSearching || !!resetData.query, !options.protyle.disabled && !hasClosestByAttribute(options.blockElement, "data-type", "NodeBlockQueryEmbed"))}
|
||||||
|
<div class="av__kanban">
|
||||||
|
${bodyHTML}
|
||||||
|
</div>
|
||||||
|
<div class="av__cursor" contenteditable="true">${Constants.ZWSP}</div>
|
||||||
|
</div>`;
|
||||||
|
} else {
|
||||||
|
options.blockElement.querySelector(".av__kanban").innerHTML = bodyHTML;
|
||||||
|
}
|
||||||
|
afterRenderGallery({
|
||||||
|
resetData,
|
||||||
|
renderAll: options.renderAll,
|
||||||
|
data,
|
||||||
|
cb: options.cb,
|
||||||
|
protyle: options.protyle,
|
||||||
|
blockElement: options.blockElement,
|
||||||
|
});
|
||||||
|
if (view.hideAttrViewName) {
|
||||||
|
options.blockElement.querySelector(".av__gallery").classList.add("av__gallery--top");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import {getFieldsByData} from "./view";
|
||||||
export const getLayoutHTML = (data: IAV) => {
|
export const getLayoutHTML = (data: IAV) => {
|
||||||
let html = "";
|
let html = "";
|
||||||
const view = data.view as IAVGallery;
|
const view = data.view as IAVGallery;
|
||||||
if (data.viewType === "gallery") {
|
if (data.viewType === "gallery" || data.viewType === "kanban") {
|
||||||
let coverFromTitle = "";
|
let coverFromTitle = "";
|
||||||
if (view.coverFrom === 0) {
|
if (view.coverFrom === 0) {
|
||||||
coverFromTitle = window.siyuan.languages.calcOperatorNone;
|
coverFromTitle = window.siyuan.languages.calcOperatorNone;
|
||||||
|
|
@ -52,7 +52,7 @@ export const getLayoutHTML = (data: IAV) => {
|
||||||
<input data-type="toggle-gallery-name" type="checkbox" class="b3-switch b3-switch--menu" ${view.displayFieldName ? "checked" : ""}>
|
<input data-type="toggle-gallery-name" type="checkbox" class="b3-switch b3-switch--menu" ${view.displayFieldName ? "checked" : ""}>
|
||||||
</label>`;
|
</label>`;
|
||||||
}
|
}
|
||||||
return `<div class="b3-menu__items">
|
html = `<div class="b3-menu__items">
|
||||||
<div class="b3-menu__items">
|
<div class="b3-menu__items">
|
||||||
<button class="b3-menu__item" data-type="nobg">
|
<button class="b3-menu__item" data-type="nobg">
|
||||||
<span class="block__icon" style="padding: 8px;margin-left: -4px;" data-type="go-config">
|
<span class="block__icon" style="padding: 8px;margin-left: -4px;" data-type="go-config">
|
||||||
|
|
@ -68,6 +68,11 @@ export const getLayoutHTML = (data: IAV) => {
|
||||||
<div class="fn__hr"></div>
|
<div class="fn__hr"></div>
|
||||||
<div>${window.siyuan.languages.table}</div>
|
<div>${window.siyuan.languages.table}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div data-type="set-layout" data-view-type="kanban" class="av__layout-item${data.viewType === "kanban" ? " av__layout-item--select" : ""}">
|
||||||
|
<svg><use xlink:href="#iconBoard"></use></svg>
|
||||||
|
<div class="fn__hr"></div>
|
||||||
|
<div>${window.siyuan.languages.kanban}</div>
|
||||||
|
</div>
|
||||||
<div data-type="set-layout" data-view-type="gallery" class="av__layout-item${data.viewType === "gallery" ? " av__layout-item--select" : ""}">
|
<div data-type="set-layout" data-view-type="gallery" class="av__layout-item${data.viewType === "gallery" ? " av__layout-item--select" : ""}">
|
||||||
<svg><use xlink:href="#iconGallery"></use></svg>
|
<svg><use xlink:href="#iconGallery"></use></svg>
|
||||||
<div class="fn__hr"></div>
|
<div class="fn__hr"></div>
|
||||||
|
|
@ -90,8 +95,21 @@ export const getLayoutHTML = (data: IAV) => {
|
||||||
<span class="fn__flex-center">${window.siyuan.languages.wrapAllFields}</span>
|
<span class="fn__flex-center">${window.siyuan.languages.wrapAllFields}</span>
|
||||||
<span class="fn__space fn__flex-1"></span>
|
<span class="fn__space fn__flex-1"></span>
|
||||||
<input data-type="toggle-entries-wrap" type="checkbox" class="b3-switch b3-switch--menu" ${view.wrapField ? "checked" : ""}>
|
<input data-type="toggle-entries-wrap" type="checkbox" class="b3-switch b3-switch--menu" ${view.wrapField ? "checked" : ""}>
|
||||||
</label>
|
</label>`;
|
||||||
<button class="b3-menu__item" data-type="set-page-size" data-size="${view.pageSize}">
|
if (data.viewType === "kanban") {
|
||||||
|
html += `<button class="b3-menu__item" data-type="set-kanban-group">
|
||||||
|
<span class="fn__flex-center">${window.siyuan.languages.groups}</span>
|
||||||
|
<span class="fn__flex-1"></span>
|
||||||
|
<span class="b3-menu__accelerator">${view.cardSize === 0 ? window.siyuan.languages.small : (view.cardSize === 1 ? window.siyuan.languages.medium : window.siyuan.languages.large)}</span>
|
||||||
|
<svg class="b3-menu__icon b3-menu__icon--small"><use xlink:href="#iconRight"></use></svg>
|
||||||
|
</button>
|
||||||
|
<label class="b3-menu__item">
|
||||||
|
<span class="fn__flex-center">${window.siyuan.languages.useBackground}</span>
|
||||||
|
<span class="fn__space fn__flex-1"></span>
|
||||||
|
<input data-type="toggle-kanban-bg" type="checkbox" class="b3-switch b3-switch--menu" ${view.displayFieldName ? "checked" : ""}>
|
||||||
|
</label>`;
|
||||||
|
}
|
||||||
|
return html + `<button class="b3-menu__item" data-type="set-page-size" data-size="${view.pageSize}">
|
||||||
<span class="fn__flex-center">${window.siyuan.languages.entryNum}</span>
|
<span class="fn__flex-center">${window.siyuan.languages.entryNum}</span>
|
||||||
<span class="fn__flex-1"></span>
|
<span class="fn__flex-1"></span>
|
||||||
<span class="b3-menu__accelerator">${view.pageSize === Constants.SIZE_DATABASE_MAZ_SIZE ? window.siyuan.languages.all : view.pageSize}</span>
|
<span class="b3-menu__accelerator">${view.pageSize === Constants.SIZE_DATABASE_MAZ_SIZE ? window.siyuan.languages.all : view.pageSize}</span>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import {escapeAriaLabel, escapeAttr, escapeHtml} from "../../../util/escape";
|
||||||
import {electronUndo} from "../../undo";
|
import {electronUndo} from "../../undo";
|
||||||
import {isInAndroid, isInHarmony, isInIOS} from "../../util/compatibility";
|
import {isInAndroid, isInHarmony, isInIOS} from "../../util/compatibility";
|
||||||
import {isMobile} from "../../../util/functions";
|
import {isMobile} from "../../../util/functions";
|
||||||
import {renderGallery} from "./gallery/render";
|
import {renderKanban, renderGallery} from "./gallery/render";
|
||||||
import {getFieldsByData, getViewIcon} from "./view";
|
import {getFieldsByData, getViewIcon} from "./view";
|
||||||
import {openMenuPanel} from "./openMenuPanel";
|
import {openMenuPanel} from "./openMenuPanel";
|
||||||
import {getPageSize} from "./groups";
|
import {getPageSize} from "./groups";
|
||||||
|
|
@ -467,6 +467,10 @@ export const avRender = (element: Element, protyle: IProtyle, cb?: (data: IAV) =
|
||||||
renderGallery({blockElement: e, protyle, cb, renderAll});
|
renderGallery({blockElement: e, protyle, cb, renderAll});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (e.getAttribute("data-av-type") === "kanban") {
|
||||||
|
renderKanban({blockElement: e, protyle, cb, renderAll});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let selectCellId;
|
let selectCellId;
|
||||||
const selectCellElement = e.querySelector(".av__cell--select") as HTMLElement;
|
const selectCellElement = e.querySelector(".av__cell--select") as HTMLElement;
|
||||||
|
|
|
||||||
|
|
@ -344,6 +344,25 @@ export const addView = (protyle: IProtyle, blockElement: Element) => {
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
addMenu.addItem({
|
||||||
|
icon: "iconBoard",
|
||||||
|
label: window.siyuan.languages.kanban,
|
||||||
|
click() {
|
||||||
|
transaction(protyle, [{
|
||||||
|
action: "addAttrViewView",
|
||||||
|
avID,
|
||||||
|
layout: "kanban",
|
||||||
|
id,
|
||||||
|
blockID: blockElement.getAttribute("data-node-id")
|
||||||
|
}], [{
|
||||||
|
action: "removeAttrViewView",
|
||||||
|
layout: "kanban",
|
||||||
|
avID,
|
||||||
|
id,
|
||||||
|
blockID: blockElement.getAttribute("data-node-id")
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
});
|
||||||
addMenu.addItem({
|
addMenu.addItem({
|
||||||
icon: "iconGallery",
|
icon: "iconGallery",
|
||||||
label: window.siyuan.languages.gallery,
|
label: window.siyuan.languages.gallery,
|
||||||
|
|
@ -377,6 +396,8 @@ export const getViewIcon = (type: string) => {
|
||||||
return "iconTable";
|
return "iconTable";
|
||||||
case "gallery":
|
case "gallery":
|
||||||
return "iconGallery";
|
return "iconGallery";
|
||||||
|
case "kanban":
|
||||||
|
return "iconBoard";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -386,6 +407,8 @@ export const getViewName = (type: string) => {
|
||||||
return window.siyuan.languages.table;
|
return window.siyuan.languages.table;
|
||||||
case "gallery":
|
case "gallery":
|
||||||
return window.siyuan.languages.gallery;
|
return window.siyuan.languages.gallery;
|
||||||
|
case "kanban":
|
||||||
|
return window.siyuan.languages.kanban;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
2
app/src/types/index.d.ts
vendored
2
app/src/types/index.d.ts
vendored
|
|
@ -88,7 +88,7 @@ type TEventBus = "ws-main" | "sync-start" | "sync-end" | "sync-fail" |
|
||||||
"lock-screen" |
|
"lock-screen" |
|
||||||
"mobile-keyboard-show" | "mobile-keyboard-hide" |
|
"mobile-keyboard-show" | "mobile-keyboard-hide" |
|
||||||
"code-language-update" | "code-language-change"
|
"code-language-update" | "code-language-change"
|
||||||
type TAVView = "table" | "gallery"
|
type TAVView = "table" | "gallery" | "kanban"
|
||||||
type TAVCol =
|
type TAVCol =
|
||||||
"text"
|
"text"
|
||||||
| "date"
|
| "date"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue