diff --git a/app/appearance/langs/en_US.json b/app/appearance/langs/en_US.json index 9d94cbe1f..9bed6d199 100644 --- a/app/appearance/langs/en_US.json +++ b/app/appearance/langs/en_US.json @@ -22,7 +22,7 @@ "new": "New", "share2LiandiConfirmTip": "Are you sure to share this document to Liandi?", "share2Liandi": "Share to Liandi", - "noDueCard": "\uD83D\uDD2E Great job! There are no more review tasks at the moment, check back later!", + "noDueCard": "Great job! There are no more review tasks at the moment, check back later!", "createDeck": "Create Deck", "addDeck": "Add to deck", "removeDeck": "Remove from deck", diff --git a/app/appearance/langs/es_ES.json b/app/appearance/langs/es_ES.json index 2aed4bf35..d0e11f424 100644 --- a/app/appearance/langs/es_ES.json +++ b/app/appearance/langs/es_ES.json @@ -22,7 +22,7 @@ "new": "Nuevo", "share2LiandiConfirmTip": "¿Estás seguro de compartir este documento con Liandi?", "share2Liandi": "Compartir con Liandi", - "noDueCard": "\uD83D\uDD2E ¡Buen trabajo! No hay más tareas de revisión en este momento, ¡vuelve a comprobar más tarde!", + "noDueCard": "¡Buen trabajo! No hay más tareas de revisión en este momento, ¡vuelve a comprobar más tarde!", "createDeck": "Crear mazo", "addDeck": "Añadir al mazo", "removeDeck": "Eliminar del mazo", diff --git a/app/appearance/langs/fr_FR.json b/app/appearance/langs/fr_FR.json index bcb15382c..766d5b756 100644 --- a/app/appearance/langs/fr_FR.json +++ b/app/appearance/langs/fr_FR.json @@ -22,7 +22,7 @@ "new": "Nouveau", "share2LiandiConfirmTip": "Êtes-vous sûr de partager ce document avec Liandi ?", "share2Liandi": "Partager avec Liandi", - "noDueCard": "\uD83D\uDD2E Excellent travail ! Il n'y a plus de tâches de révision pour le moment, revenez plus tard !", + "noDueCard": "Excellent travail ! Il n'y a plus de tâches de révision pour le moment, revenez plus tard !", "createDeck": "Créer un deck", "addDeck": "Ajouter au deck", "removeDeck": "Retirer du deck", diff --git a/app/appearance/langs/zh_CHT.json b/app/appearance/langs/zh_CHT.json index fa1a15154..08ac93573 100644 --- a/app/appearance/langs/zh_CHT.json +++ b/app/appearance/langs/zh_CHT.json @@ -22,7 +22,7 @@ "new": "新建", "share2LiandiConfirmTip": "確定將該文檔分享到鏈滴嗎?", "share2Liandi": "分享到鏈滴", - "noDueCard": "\uD83D\uDD2E 幹得漂亮!目前已經沒有更多複習任務,過一會再來看看吧!", + "noDueCard": "幹得漂亮!目前已經沒有更多複習任務,過一會再來看看吧!", "createDeck": "創建卡包", "addDeck": "加入卡包", "removeDeck": "從卡包中移除", diff --git a/app/appearance/langs/zh_CN.json b/app/appearance/langs/zh_CN.json index 6f565df13..45374b71e 100644 --- a/app/appearance/langs/zh_CN.json +++ b/app/appearance/langs/zh_CN.json @@ -22,7 +22,7 @@ "new": "新建", "share2LiandiConfirmTip": "确定将该文档分享到链滴吗?", "share2Liandi": "分享到链滴", - "noDueCard": "\uD83D\uDD2E 干得漂亮!目前已经没有更多复习任务,过一会再来看看吧!", + "noDueCard": "干得漂亮!目前已经没有更多复习任务,过一会再来看看吧!", "createDeck": "创建卡包", "addDeck": "加入卡包", "removeDeck": "从卡包中移除", diff --git a/app/src/assets/scss/_dialog.scss b/app/src/assets/scss/_dialog.scss index 333a0b5ee..1ad836d4d 100644 --- a/app/src/assets/scss/_dialog.scss +++ b/app/src/assets/scss/_dialog.scss @@ -118,17 +118,25 @@ flex-direction: column; flex: 1; text-align: center; - color: var(--b3-theme-on-surface); background-color: var(--b3-theme-background); font-size: 16px; + + & > div { + font-size: 64px; + margin-bottom: 16px; + } } - &__cardaction > div > span { - display: block; - color: var(--b3-theme-on-surface); - text-align: center; - line-height: 15px; - font-size: 10px; + &__cardaction { + padding: 16px 24px; + + & > div > span { + display: block; + color: var(--b3-theme-on-surface); + text-align: center; + line-height: 15px; + font-size: 10px; + } } &__cardblock { diff --git a/app/src/card/makeCard.ts b/app/src/card/makeCard.ts index 3ce5acf32..a27264425 100644 --- a/app/src/card/makeCard.ts +++ b/app/src/card/makeCard.ts @@ -7,7 +7,7 @@ import {confirmDialog} from "../dialog/confirmDialog"; import {hideElements} from "../protyle/ui/hideElements"; import {viewCards} from "./viewCards"; -export const genCardItem = (item: ICard) => { +export const genCardItem = (item: ICardPackage) => { return `
  • ${item.name} ${item.size} @@ -48,7 +48,7 @@ export const makeCard = (nodeElement: Element[]) => { } ids.push(item.getAttribute("data-node-id")); }); - response.data.forEach((item: ICard) => { + response.data.forEach((item: ICardPackage) => { html += genCardItem(item); }); const dialog = new Dialog({ @@ -170,5 +170,19 @@ export const makeCard = (nodeElement: Element[]) => { }); }; +export const quickMakeCard = (nodeElement: Element[]) => { + const ids: string[] = []; + nodeElement.forEach(item => { + if (item.getAttribute("data-type") === "NodeThematicBreak") { + return; + } + ids.push(item.getAttribute("data-node-id")); + }); + fetchPost("/api/riff/addRiffCards", { + deckID: "20230218211946-2kw8jgx", + blockIDs: ids + }); +} + diff --git a/app/src/card/openCard.ts b/app/src/card/openCard.ts index 0ff2c0586..c2041ef2d 100644 --- a/app/src/card/openCard.ts +++ b/app/src/card/openCard.ts @@ -23,29 +23,38 @@ export const openCard = () => { decksHTML += ``; }); fetchPost("/api/riff/getRiffDueCards", {deckID: ""}, (cardsResponse) => { - let blocks = cardsResponse.data; - let countHTML = ""; - let index = 0; - if (blocks.length > 0) { - countHTML = `1/${blocks.length}`; - } - const dialog = new Dialog({ - title: window.siyuan.languages.riffCard, - content: `
    -
    - - - - - - -
    ${countHTML}
    + openCardByData(cardsResponse.data, ``) + }); + }); +}; + +export const openCardByData = (cardsData: ICard[], html = "") => { + let blocks = cardsData; + let index = 0; + if (blocks.length > 0) { + html += `
    + + + + + +
    1/${blocks.length}
    +
    `; + } + const dialog = new Dialog({ + content: `
    +
    + ${window.siyuan.languages.riffCard} + ${html}
    -
    ${window.siyuan.languages.noDueCard}
    +
    +
    🎉
    + ${window.siyuan.languages.noDueCard} +
    - +
    @@ -70,22 +79,96 @@ export const openCard = () => {
    `, - width: isMobile() ? "98vw" : "80vw", - height: isMobile() ? "80vh" : "70vh", + width: isMobile() ? "98vw" : "80vw", + height: isMobile() ? "80vh" : "70vh", + }); + (dialog.element.querySelector(".b3-dialog__scrim") as HTMLElement).style.backgroundColor = "var(--b3-theme-background)"; + const editor = new Protyle(dialog.element.querySelector("[data-type='render']") as HTMLElement, { + blockId: "", + action: [Constants.CB_GET_ALL], + render: { + background: false, + title: false, + gutter: true, + breadcrumbDocName: true, + }, + typewriterMode: false + }); + if (blocks.length > 0) { + fetchPost("/api/filetree/getDoc", { + id: blocks[index].blockID, + mode: 0, + size: Constants.SIZE_GET_MAX + }, (response) => { + onGet(response, editor.protyle, [Constants.CB_GET_ALL, Constants.CB_GET_HTML]); + }); + } + (dialog.element.firstElementChild as HTMLElement).style.zIndex = "200"; + dialog.element.setAttribute("data-key", window.siyuan.config.keymap.general.riffCard.custom); + const countElement = dialog.element.querySelector('[data-type="count"]'); + const actionElements = dialog.element.querySelectorAll(".b3-dialog__cardaction"); + dialog.element.addEventListener("click", (event) => { + const viewElement = hasClosestByAttribute(event.target as HTMLElement, "data-type", "view"); + if (viewElement) { + // TODO 文档卡 + viewCards(selectElement.value, selectElement.options[selectElement.selectedIndex].text); + event.preventDefault(); + event.stopPropagation(); + return; + } + let type = ""; + if (typeof event.detail === "string") { + if (event.detail === "a") { + type = "0"; + } else if (event.detail === "h") { + type = "1"; + } else if (event.detail === "g") { + type = "2"; + } else if (event.detail === "e") { + type = "3"; + } else if (event.detail === "s") { + type = "-1"; + } + } + if (!type) { + const buttonElement = hasClosestByClassName(event.target as HTMLElement, "b3-button"); + if (buttonElement) { + type = buttonElement.getAttribute("data-type"); + } + } + if (!type || !blocks[index]) { + return; + } + event.preventDefault(); + event.stopPropagation(); + if (type === "-1") { + editor.protyle.element.classList.remove("b3-dialog__cardblock--hide"); + actionElements[0].classList.add("fn__none"); + actionElements[1].querySelectorAll(".b3-button").forEach((element, btnIndex) => { + element.previousElementSibling.textContent = blocks[index].nextDues[btnIndex]; }); - (dialog.element.querySelector(".b3-dialog__scrim") as HTMLElement).style.backgroundColor = "var(--b3-theme-background)"; - const editor = new Protyle(dialog.element.querySelector("[data-type='render']") as HTMLElement, { - blockId: "", - action: [Constants.CB_GET_ALL], - render: { - background: false, - title: false, - gutter: true, - breadcrumbDocName: true, - }, - typewriterMode: false - }); - if (blocks.length > 0) { + actionElements[1].classList.remove("fn__none"); + return; + } + if (["0", "1", "2", "3"].includes(type)) { + fetchPost("/api/riff/reviewRiffCard", { + deckID: blocks[index].deckID, + blockID: blocks[index].blockID, + rating: parseInt(type) + }, () => { + index++; + editor.protyle.element.classList.add("b3-dialog__cardblock--hide"); + if (index > blocks.length - 1) { + countElement.classList.add("fn__none"); + editor.protyle.element.classList.add("fn__none"); + editor.protyle.element.nextElementSibling.classList.remove("fn__none"); + actionElements[0].classList.add("fn__none"); + actionElements[1].classList.add("fn__none"); + return; + } + actionElements[0].classList.remove("fn__none"); + actionElements[1].classList.add("fn__none"); + countElement.lastElementChild.firstElementChild.innerHTML = (index + 1).toString(); fetchPost("/api/filetree/getDoc", { id: blocks[index].blockID, mode: 0, @@ -93,111 +176,39 @@ export const openCard = () => { }, (response) => { onGet(response, editor.protyle, [Constants.CB_GET_ALL, Constants.CB_GET_HTML]); }); - } - (dialog.element.firstElementChild as HTMLElement).style.zIndex = "200"; - dialog.element.setAttribute("data-key", window.siyuan.config.keymap.general.riffCard.custom); - const countElement = dialog.element.querySelector('[data-type="count"]'); - const actionElements = dialog.element.querySelectorAll(".b3-dialog__cardaction"); - const selectElement = dialog.element.querySelector("select"); - selectElement.addEventListener("change", () => { - fetchPost("/api/riff/getRiffDueCards", {deckID: selectElement.value}, (cardsChangeResponse) => { - blocks = cardsChangeResponse.data; - index = 0; - editor.protyle.element.classList.add("b3-dialog__cardblock--hide"); - if (blocks.length > 0) { - countElement.innerHTML = `1/${blocks.length}`; - countElement.classList.remove("fn__none"); - editor.protyle.element.classList.remove("fn__none"); - editor.protyle.element.nextElementSibling.classList.add("fn__none"); - actionElements[0].classList.remove("fn__none"); - actionElements[1].classList.add("fn__none"); - fetchPost("/api/filetree/getDoc", { - id: blocks[index].blockID, - mode: 0, - size: Constants.SIZE_GET_MAX - }, (response) => { - onGet(response, editor.protyle, [Constants.CB_GET_ALL, Constants.CB_GET_HTML]); - }); - } else { - countElement.classList.add("fn__none"); - editor.protyle.element.classList.add("fn__none"); - editor.protyle.element.nextElementSibling.classList.remove("fn__none"); - actionElements[0].classList.add("fn__none"); - actionElements[1].classList.add("fn__none"); - } + }); + } + }); + const selectElement = dialog.element.querySelector("select"); + if (!selectElement) { + return + } + selectElement.addEventListener("change", () => { + fetchPost("/api/riff/getRiffDueCards", {deckID: selectElement.value}, (cardsChangeResponse) => { + blocks = cardsChangeResponse.data; + index = 0; + editor.protyle.element.classList.add("b3-dialog__cardblock--hide"); + if (blocks.length > 0) { + countElement.lastElementChild.innerHTML = `1/${blocks.length}`; + countElement.classList.remove("fn__none"); + editor.protyle.element.classList.remove("fn__none"); + editor.protyle.element.nextElementSibling.classList.add("fn__none"); + actionElements[0].classList.remove("fn__none"); + actionElements[1].classList.add("fn__none"); + fetchPost("/api/filetree/getDoc", { + id: blocks[index].blockID, + mode: 0, + size: Constants.SIZE_GET_MAX + }, (response) => { + onGet(response, editor.protyle, [Constants.CB_GET_ALL, Constants.CB_GET_HTML]); }); - }); - dialog.element.addEventListener("click", (event) => { - const viewElement = hasClosestByAttribute(event.target as HTMLElement, "data-type", "view"); - if (viewElement) { - viewCards(selectElement.value, selectElement.options[selectElement.selectedIndex].text); - event.preventDefault(); - event.stopPropagation(); - return; - } - let type = ""; - if (typeof event.detail === "string") { - if (event.detail === "a") { - type = "0"; - } else if (event.detail === "h") { - type = "1"; - } else if (event.detail === "g") { - type = "2"; - } else if (event.detail === "e") { - type = "3"; - } else if (event.detail === "s") { - type = "-1"; - } - } - if (!type) { - const buttonElement = hasClosestByClassName(event.target as HTMLElement, "b3-button"); - if (buttonElement) { - type = buttonElement.getAttribute("data-type"); - } - } - if (!type || !blocks[index]) { - return; - } - event.preventDefault(); - event.stopPropagation(); - if (type === "-1") { - editor.protyle.element.classList.remove("b3-dialog__cardblock--hide"); - actionElements[0].classList.add("fn__none"); - actionElements[1].querySelectorAll(".b3-button").forEach((element, btnIndex) => { - element.previousElementSibling.textContent = blocks[index].nextDues[btnIndex]; - }); - actionElements[1].classList.remove("fn__none"); - return; - } - if (["0", "1", "2", "3"].includes(type)) { - fetchPost("/api/riff/reviewRiffCard", { - deckID: blocks[index].deckID, - blockID: blocks[index].blockID, - rating: parseInt(type) - }, () => { - index++; - editor.protyle.element.classList.add("b3-dialog__cardblock--hide"); - if (index > blocks.length - 1) { - countElement.classList.add("fn__none"); - editor.protyle.element.classList.add("fn__none"); - editor.protyle.element.nextElementSibling.classList.remove("fn__none"); - actionElements[0].classList.add("fn__none"); - actionElements[1].classList.add("fn__none"); - return; - } - actionElements[0].classList.remove("fn__none"); - actionElements[1].classList.add("fn__none"); - countElement.firstElementChild.innerHTML = (index + 1).toString(); - fetchPost("/api/filetree/getDoc", { - id: blocks[index].blockID, - mode: 0, - size: Constants.SIZE_GET_MAX - }, (response) => { - onGet(response, editor.protyle, [Constants.CB_GET_ALL, Constants.CB_GET_HTML]); - }); - }); - } - }); + } else { + countElement.classList.add("fn__none"); + editor.protyle.element.classList.add("fn__none"); + editor.protyle.element.nextElementSibling.classList.remove("fn__none"); + actionElements[0].classList.add("fn__none"); + actionElements[1].classList.add("fn__none"); + } }); }); -}; +} diff --git a/app/src/card/viewCards.ts b/app/src/card/viewCards.ts index b1e5df000..9c3e35dad 100644 --- a/app/src/card/viewCards.ts +++ b/app/src/card/viewCards.ts @@ -16,19 +16,17 @@ export const viewCards = (deckID: string, title: string, sourceElement?: HTMLEle let edit: Protyle; fetchPost("/api/riff/getRiffCards", {deckID, page: pageIndex}, (response) => { const dialog = new Dialog({ - title, content: `
    -
    -
    +
    + ${title} +
    ${pageIndex}/${response.data.pageCount || 1} -
    -
      ${renderViewItem(response.data.blocks)} diff --git a/app/src/protyle/gutter/index.ts b/app/src/protyle/gutter/index.ts index 44d5f2381..1cdabd789 100644 --- a/app/src/protyle/gutter/index.ts +++ b/app/src/protyle/gutter/index.ts @@ -32,7 +32,7 @@ import {mathRender} from "../markdown/mathRender"; import {duplicateBlock} from "../wysiwyg/commonHotkey"; import {movePathTo} from "../../util/pathName"; import {hintMoveBlock} from "../hint/extend"; -import {makeCard} from "../../card/makeCard"; +import {makeCard, quickMakeCard} from "../../card/makeCard"; import {transferBlockRef} from "../../menus/block"; export class Gutter { @@ -667,7 +667,15 @@ export class Gutter { this.genWidths(selectsElement, protyle); window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); window.siyuan.menus.menu.append(new MenuItem({ - label: window.siyuan.languages.riffCard, + label: window.siyuan.languages.quickMakeCard, + iconHTML:``, + icon: "iconRiffCard", + click() { + quickMakeCard(selectsElement); + } + }).element); + window.siyuan.menus.menu.append(new MenuItem({ + label: window.siyuan.languages.addToDeck, icon: "iconRiffCard", click() { makeCard(selectsElement); @@ -1431,7 +1439,15 @@ export class Gutter { } if (type !== "NodeThematicBreak") { window.siyuan.menus.menu.append(new MenuItem({ - label: window.siyuan.languages.riffCard, + label: window.siyuan.languages.quickMakeCard, + iconHTML:``, + icon: "iconRiffCard", + click() { + quickMakeCard([nodeElement]); + } + }).element); + window.siyuan.menus.menu.append(new MenuItem({ + label: window.siyuan.languages.addToDeck, icon: "iconRiffCard", click() { makeCard([nodeElement]); diff --git a/app/src/protyle/header/Title.ts b/app/src/protyle/header/Title.ts index b56947def..226aa4404 100644 --- a/app/src/protyle/header/Title.ts +++ b/app/src/protyle/header/Title.ts @@ -33,6 +33,7 @@ import {genEmptyElement} from "../../block/util"; import {transaction} from "../wysiwyg/transaction"; import {hideTooltip} from "../../dialog/tooltip"; import {transferBlockRef} from "../../menus/block"; +import {openCardByData} from "../../card/openCard"; export class Title { public element: HTMLElement; @@ -230,7 +231,9 @@ export class Title { }).element); window.siyuan.menus.menu.popup({x: event.clientX, y: event.clientY}); }); - this.element.querySelector(".protyle-attr").addEventListener("click", (event: MouseEvent & { target: HTMLElement }) => { + this.element.querySelector(".protyle-attr").addEventListener("click", (event: MouseEvent & { + target: HTMLElement + }) => { fetchPost("/api/block/getDocInfo", { id: protyle.block.rootID }, (response) => { @@ -353,6 +356,15 @@ export class Title { openFileWechatNotify(protyle); } }).element); + window.siyuan.menus.menu.append(new MenuItem({ + label: window.siyuan.languages.riffCard, + icon: "iconRiffCard", + click: () => { + fetchPost("/api/riff/getTreeRiffDueCards", {rootID: protyle.block.rootID}, (response) => { + openCardByData(response.data, `${escapeHtml(this.editElement.textContent)}`); + }); + } + }).element); window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); window.siyuan.menus.menu.append(new MenuItem({ iconHTML: Constants.ZWSP, diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index 96f2ed503..b692a5d15 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -59,13 +59,19 @@ interface IWorkspace { closed: boolean } -interface ICard { +interface ICardPackage { id: string updated: string name: string size: number } +interface ICard { + blockID: string + deckID: string + nextDues: IObject +} + interface ISearchOption { name?: string sort: number, // 0:按块类型(默认),1:按创建时间升序,2:按创建时间降序,3:按更新时间升序,4:按更新时间降序,5:按内容顺序(仅在按文档分组时),6:按相关度升序,7:按相关度降序