This commit is contained in:
Vanessa 2023-05-20 20:47:35 +08:00
parent a1f8339d4b
commit 484647509c
9 changed files with 120 additions and 134 deletions

View file

@ -1,4 +1,5 @@
{
"color": "Color",
"confirmPassword": "I have already remembered the password",
"passwordNoMatch": "The passwords entered twice do not match",
"cloudConfigTip": "Please configure in [Settings - Cloud]",
@ -247,7 +248,7 @@
"importDataTip": "Import the exported zip archive, overwriting the <code class='fn__code'>workspace/data/</code> folder by path",
"includeChildDoc": "Include child documents",
"text": "Text",
"lastUsed": "Recently used fonts",
"lastUsed": "Apariencia usada recientemente",
"removedNotebook": "Removed notebook",
"querySyntax": "Query Syntax",
"rollback": "Rollback",

View file

@ -1,4 +1,5 @@
{
"color": "Color",
"confirmPassword": "Ya he recordado la contraseña",
"passwordNoMatch": "Las contraseñas ingresadas dos veces no coinciden",
"cloudConfigTip": "Configure en [Configuración - Nube]",
@ -247,7 +248,7 @@
"importDataTip": "Importar el archivo zip exportado, sobrescribiendo la carpeta <code class='fn__code'>workspace/data/</code> por la ruta",
"includeChildDoc": "Incluir los documentos de los niños",
"text": "Texto",
"lastUsed": "Fuentes utilizadas recientemente",
"lastUsed": "Fuentes utilizadas apariencia",
"removedNotebook": "Cuaderno de notas eliminado",
"querySyntax": "Sintaxis de consulta",
"rollback": "Rollback",

View file

@ -1,4 +1,5 @@
{
"color": "Couleur",
"confirmPassword": "J'ai déjà retenu le mot de passe",
"passwordNoMatch": "Les mots de passe saisis deux fois ne correspondent pas",
"cloudConfigTip": "Veuillez configurer dans [Paramètres - Cloud]",
@ -247,7 +248,7 @@
"importDataTip": "Importer l'archive zip exportée, en écrasant le dossier <code class='fn__code'>workspace/data/</code> par le chemin",
"includeChildDoc": "Inclure les documents enfants",
"text": "Texte",
"lastUsed": "Polices récemment utilisées",
"lastUsed": "Apparence récemment utilisée",
"removedNotebook": "Cahier supprimé",
"querySyntax": "Syntaxe de la requête",
"rollback": "Rollback",

View file

@ -1,4 +1,5 @@
{
"color": "顏色",
"confirmPassword": "我已經牢記密碼了",
"passwordNoMatch": "兩次輸入的密碼不一致",
"cloudConfigTip": "請在 [設置 - 雲端] 中進行配置",
@ -247,7 +248,7 @@
"importDataTip": "將導出的 zip 壓縮包導入,按路徑覆蓋 <code class='fn__code'>工作空間/data/</code> 文件夾",
"includeChildDoc": "包含子文檔",
"text": "文字",
"lastUsed": "最近使用過的字體",
"lastUsed": "最近使用過的外觀",
"removedNotebook": "已刪除的筆記本",
"querySyntax": "查詢語法",
"rollback": "回滾",

View file

@ -1,4 +1,5 @@
{
"color": "颜色",
"confirmPassword": "我已经牢记密码了",
"passwordNoMatch": "两次输入的密码不一致",
"cloudConfigTip": "请在 [设置 - 云端] 中进行配置",
@ -247,7 +248,7 @@
"importDataTip": "将导出的 zip 压缩包导入,按路径覆盖 <code class='fn__code'>工作空间/data/</code> 文件夹",
"includeChildDoc": "包含子文档",
"text": "文本",
"lastUsed": "最近使用过的字体",
"lastUsed": "最近使用过的外观",
"removedNotebook": "已删除的笔记本",
"querySyntax": "查询语法",
"rollback": "回滚",

View file

@ -196,7 +196,7 @@ export abstract class Constants {
moveToDown: {default: "⇧⌘↓", custom: "⇧⌘↓"},
},
insert: {
font: {default: "⌥⌘X", custom: "⌥⌘X"},
appearance: {default: "⌥⌘X", custom: "⌥⌘X"},
lastUsed: {default: "⌥X", custom: "⌥X"},
ref: {default: "⌥[", custom: "⌥["},
kbd: {default: "⌘'", custom: "⌘'"},

View file

@ -39,6 +39,8 @@ import {AIActions} from "../../ai/actions";
import {activeBlur} from "../../mobile/util/keyboardToolbar";
import {hideTooltip} from "../../dialog/tooltip";
import {App} from "../../index";
import {appearanceMenu} from "../toolbar/Font";
import {setPosition} from "../../util/setPosition";
export class Gutter {
public element: HTMLElement;
@ -676,7 +678,19 @@ export class Gutter {
window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element);
const appearanceElement = new MenuItem({
label: window.siyuan.languages.appearance,
submenu: this.genCardStyle(selectsElement, protyle).concat(this.genFontStyle(selectsElement, protyle)).concat(this.genBGStyle(selectsElement, protyle))
click() {
protyle.toolbar.element.classList.add("fn__none");
protyle.toolbar.subElement.innerHTML = "";
protyle.toolbar.subElement.style.width = "";
protyle.toolbar.subElement.style.padding = "";
protyle.toolbar.subElement.append(appearanceMenu(protyle, selectsElement));
protyle.toolbar.subElement.classList.remove("fn__none");
protyle.toolbar.subElementCloseCB = undefined;
/// #if !MOBILE
const position = selectsElement[0].getBoundingClientRect();
setPosition(protyle.toolbar.subElement, position.left, position.top);
/// #endif
}
}).element;
window.siyuan.menus.menu.append(appearanceElement);
if (!isMobile()) {
@ -1461,7 +1475,19 @@ export class Gutter {
if (!protyle.disabled) {
const appearanceElement = new MenuItem({
label: window.siyuan.languages.appearance,
submenu: this.genCardStyle([nodeElement], protyle).concat(this.genFontStyle([nodeElement], protyle)).concat(this.genBGStyle([nodeElement], protyle))
click() {
protyle.toolbar.element.classList.add("fn__none");
protyle.toolbar.subElement.innerHTML = "";
protyle.toolbar.subElement.style.width = "";
protyle.toolbar.subElement.style.padding = "";
protyle.toolbar.subElement.append(appearanceMenu(protyle, [nodeElement]));
protyle.toolbar.subElement.classList.remove("fn__none");
protyle.toolbar.subElementCloseCB = undefined;
/// #if !MOBILE
const position = nodeElement.getBoundingClientRect();
setPosition(protyle.toolbar.subElement, position.left, position.top);
/// #endif
}
}).element;
window.siyuan.menus.menu.append(appearanceElement);
if (!isMobile()) {
@ -1622,47 +1648,6 @@ export class Gutter {
}).element);
}
private genBGStyle(nodeElements: Element[], protyle: IProtyle) {
const styles: IMenu[] = [];
const isM = isMobile();
["var(--b3-font-background1)", "var(--b3-font-background2)", "var(--b3-font-background3)", "var(--b3-font-background4)",
"var(--b3-font-background5)", "var(--b3-font-background6)", "var(--b3-font-background7)", "var(--b3-font-background8)",
"var(--b3-font-background9)", "var(--b3-font-background10)", "var(--b3-font-background11)", "var(--b3-font-background12)",
"var(--b3-font-background13)"].forEach((item, index) => {
styles.push({
iconHTML: isM ? `<span style="background-color:${item};" class="color__square fn__flex-center"></span>` : Constants.ZWSP,
label: isM ? `${window.siyuan.languages.colorPrimary} ${index + 1}` : `<div class="fn__flex" data-type="a" aria-label="${window.siyuan.languages.colorPrimary} ${index + 1}">
<span style="background-color:${item};" class="color__square fn__flex-center"></span>
</div>`,
click: () => {
this.genClick(nodeElements, protyle, (e: HTMLElement) => {
e.style.backgroundColor = item;
});
}
});
});
styles.push({
type: "separator"
});
styles.push({
iconHTML: isM ? '<span class="color__square fn__flex-center">A</span>' : Constants.ZWSP,
label: isM ? window.siyuan.languages.clearFontStyle : `<div class="fn__flex" data-type="a" aria-label="${window.siyuan.languages.clearFontStyle}">
<span class="color__square fn__flex-center">A</span>
</div>`,
click: () => {
this.genClick(nodeElements, protyle, (e: HTMLElement) => {
e.style.color = "";
e.style.webkitTextFillColor = "";
e.style.webkitTextStroke = "";
e.style.textShadow = "";
e.style.backgroundColor = "";
e.style.fontSize = "";
});
}
});
return styles;
}
private genWidths(nodeElements: Element[], protyle: IProtyle) {
const styles: IMenu[] = [];
["25%", "33%", "50%", "67%", "75%"].forEach((item) => {
@ -1740,77 +1725,6 @@ export class Gutter {
}).element);
}
private genFontStyle(nodeElements: Element[], protyle: IProtyle) {
const styles: IMenu[] = [];
const isM = isMobile();
["var(--b3-font-color1)", "var(--b3-font-color2)", "var(--b3-font-color3)", "var(--b3-font-color4)",
"var(--b3-font-color5)", "var(--b3-font-color6)", "var(--b3-font-color7)", "var(--b3-font-color8)",
"var(--b3-font-color9)", "var(--b3-font-color10)", "var(--b3-font-color11)", "var(--b3-font-color12)",
"var(--b3-font-color13)"].forEach((item, index) => {
styles.push({
iconHTML: isM ? `<span style="color:${item};" class="color__square fn__flex-center">A</span>` : Constants.ZWSP,
label: isM ? `${window.siyuan.languages.colorFont} ${index + 1}` : `<div class="fn__flex" data-type="a" aria-label="${window.siyuan.languages.colorFont} ${index + 1}">
<span style="color:${item};" class="color__square fn__flex-center">A</span>
</div>`,
click: () => {
this.genClick(nodeElements, protyle, (e: HTMLElement) => {
e.style.color = item;
});
}
});
});
styles.push({
type: "separator"
});
return styles;
}
private genCardStyle(nodeElements: Element[], protyle: IProtyle) {
const styles: IMenu[] = [];
const isM = isMobile();
["error", "warning", "info", "success"].forEach((item) => {
styles.push({
iconHTML: isM ? `<span style="color: var(--b3-card-${item}-color);background-color: var(--b3-card-${item}-background);" class="color__square fn__flex-center">A</span>` : Constants.ZWSP,
label: isM ? window.siyuan.languages[item + "Style"] : `<div class="fn__flex" data-type="a" aria-label="${window.siyuan.languages[item + "Style"]}">
<span style="color: var(--b3-card-${item}-color);background-color: var(--b3-card-${item}-background);" class="color__square fn__flex-center">A</span>
</div>`,
click: () => {
this.genClick(nodeElements, protyle, (e: HTMLElement) => {
e.style.color = `var(--b3-card-${item}-color)`;
e.style.backgroundColor = `var(--b3-card-${item}-background)`;
});
}
});
});
styles.push({
type: "separator"
});
return styles.concat([{
iconHTML: isM ? '<span style="-webkit-text-stroke: 0.2px var(--b3-theme-on-background);-webkit-text-fill-color : transparent;" class="color__square fn__flex-center">A</span>' : Constants.ZWSP,
label: isM ? window.siyuan.languages.hollow : `<div class="fn__flex" data-type="a" aria-label="${window.siyuan.languages.hollow}">
<span style="-webkit-text-stroke: 0.2px var(--b3-theme-on-background);-webkit-text-fill-color : transparent;" class="color__square fn__flex-center">A</span>
</div>`,
click: () => {
this.genClick(nodeElements, protyle, (e: HTMLElement) => {
e.style.webkitTextStroke = "0.2px var(--b3-theme-on-background)";
e.style.webkitTextFillColor = "transparent";
});
}
}, {
iconHTML: isM ? ' <span style="text-shadow: 1px 1px var(--b3-theme-surface-lighter), 2px 2px var(--b3-theme-surface-lighter), 3px 3px var(--b3-theme-surface-lighter), 4px 4px var(--b3-theme-surface-lighter)" class="color__square fn__flex-center">A</span>' : Constants.ZWSP,
label: isM ? window.siyuan.languages.shadow : `<div class="fn__flex" data-type="a" aria-label="${window.siyuan.languages.shadow}">
<span style="text-shadow: 1px 1px var(--b3-theme-surface-lighter), 2px 2px var(--b3-theme-surface-lighter), 3px 3px var(--b3-theme-surface-lighter), 4px 4px var(--b3-theme-surface-lighter)" class="color__square fn__flex-center">A</span>
</div>`,
click: () => {
this.genClick(nodeElements, protyle, (e: HTMLElement) => {
e.style.textShadow = "1px 1px var(--b3-theme-surface-lighter), 2px 2px var(--b3-theme-surface-lighter), 3px 3px var(--b3-theme-surface-lighter), 4px 4px var(--b3-theme-surface-lighter)";
});
}
}, {
type: "separator"
}]);
}
private genCopyTextRef(selectsElement: Element[]): false | IMenu {
if (isNotEditBlock(selectsElement[0])) {
return false;

View file

@ -1,9 +1,10 @@
import {setStorageVal, updateHotkeyTip} from "../util/compatibility";
import {ToolbarItem} from "./ToolbarItem";
import {setPosition} from "../../util/setPosition";
import {focusByRange, getSelectionPosition} from "../util/selection";
import {focusBlock, focusByRange, getSelectionPosition} from "../util/selection";
import {Constants} from "../../constants";
import {hasClosestByAttribute} from "../util/hasClosest";
import {updateBatchTransaction} from "../wysiwyg/transaction";
export class Font extends ToolbarItem {
public element: HTMLElement;
@ -18,7 +19,7 @@ export class Font extends ToolbarItem {
protyle.toolbar.subElement.innerHTML = "";
protyle.toolbar.subElement.style.width = "";
protyle.toolbar.subElement.style.padding = "";
protyle.toolbar.subElement.append(fontMenu(protyle));
protyle.toolbar.subElement.append(appearanceMenu(protyle));
protyle.toolbar.subElement.classList.remove("fn__none");
protyle.toolbar.subElementCloseCB = undefined;
focusByRange(protyle.toolbar.range);
@ -30,7 +31,7 @@ export class Font extends ToolbarItem {
}
}
const fontMenu = (protyle: IProtyle) => {
export const appearanceMenu = (protyle: IProtyle, nodeElements?: Element[]) => {
let colorHTML = "";
["var(--b3-font-color1)", "var(--b3-font-color2)", "var(--b3-font-color3)", "var(--b3-font-color4)",
"var(--b3-font-color5)", "var(--b3-font-color6)", "var(--b3-font-color7)", "var(--b3-font-color8)",
@ -76,20 +77,39 @@ const fontMenu = (protyle: IProtyle) => {
case "fontSize":
lastColorHTML += `<button data-type="${lastFontStatus[0]}" class="protyle-font__style">${lastFontStatus[1]}</button>`;
break;
case "style1":
lastColorHTML += `<button data-type="${lastFontStatus[0]}" style="background-color:${lastFontStatus[1]};color:${lastFontStatus[2]}" class="color__square">A</button>`;
break;
}
});
lastColorHTML += "</div>";
}
let textElement = protyle.toolbar.range.cloneContents().querySelector('[data-type~="text"]') as HTMLElement;
let textElement: HTMLElement
let fontSize = "16px";
if (!textElement) {
textElement = hasClosestByAttribute(protyle.toolbar.range.startContainer, "data-type", "text") as HTMLElement;
if (nodeElements) {
if (nodeElements.length === 1) {
textElement = nodeElements[0] as HTMLElement
}
} else {
textElement = protyle.toolbar.range.cloneContents().querySelector('[data-type~="text"]') as HTMLElement;
if (!textElement) {
textElement = hasClosestByAttribute(protyle.toolbar.range.startContainer, "data-type", "text") as HTMLElement;
}
}
if (textElement) {
fontSize = textElement.style.fontSize || "16px";
}
element.innerHTML = `${lastColorHTML}
<div class="fn__hr"></div>
<div>${window.siyuan.languages.color}</div>
<div class="fn__hr--small"></div>
<div class="fn__flex">
<button class="color__square" data-type="style1" style="color: var(--b3-card-error-color);background-color: var(--b3-card-error-background);">A</button>
<button class="color__square" data-type="style1" style="color: var(--b3-card-warning-color);background-color: var(--b3-card-warning-background);">A</button>
<button class="color__square" data-type="style1" style="color: var(--b3-card-info-color);background-color: var(--b3-card-info-background);">A</button>
<button class="color__square" data-type="style1" style="color: var(--b3-card-success-color);background-color: var(--b3-card-success-background);">A</button>
</div>
<div class="fn__hr"></div>
<div>${window.siyuan.languages.colorFont}</div>
<div class="fn__hr--small"></div>
<div class="fn__flex">
@ -136,10 +156,38 @@ const fontMenu = (protyle: IProtyle) => {
while (target && !target.isEqualNode(element)) {
const dataType = target.getAttribute("data-type");
if (target.tagName === "BUTTON") {
if (dataType === "clear") {
protyle.toolbar.setInlineMark(protyle, "clear", "range", {type: "text"});
if (nodeElements) {
updateBatchTransaction(nodeElements, protyle, (e: HTMLElement) => {
if (dataType === "clear") {
e.style.color = "";
e.style.webkitTextFillColor = "";
e.style.webkitTextStroke = "";
e.style.textShadow = "";
e.style.backgroundColor = "";
e.style.fontSize = "";
} else if (dataType === "style1") {
e.style.backgroundColor = target.style.backgroundColor;
e.style.color = target.style.color;
} else if (dataType === "style2") {
e.style.webkitTextStroke = "0.2px var(--b3-theme-on-background)";
e.style.webkitTextFillColor = "transparent";
} else if (dataType === "style4") {
e.style.textShadow = "1px 1px var(--b3-theme-surface-lighter), 2px 2px var(--b3-theme-surface-lighter), 3px 3px var(--b3-theme-surface-lighter), 4px 4px var(--b3-theme-surface-lighter)";
} else if (dataType === "color") {
e.style.color = target.style.color;
} else if (dataType === "backgroundColor") {
e.style.backgroundColor = target.style.backgroundColor;
}
});
focusBlock(nodeElements[0]);
} else {
fontEvent(protyle, dataType, target.style.backgroundColor || target.style.color || target.textContent);
if (dataType === "clear") {
protyle.toolbar.setInlineMark(protyle, "clear", "range", {type: "text"});
} else if (dataType === "style1") {
fontEvent(protyle, dataType, target.style.backgroundColor + Constants.ZWSP + target.style.color);
} else {
fontEvent(protyle, dataType, target.style.backgroundColor || target.style.color || target.textContent);
}
}
break;
}
@ -147,7 +195,14 @@ const fontMenu = (protyle: IProtyle) => {
}
});
element.querySelector("select").addEventListener("change", function (event: Event) {
fontEvent(protyle, "fontSize", (event.target as HTMLSelectElement).value);
if (nodeElements) {
updateBatchTransaction(nodeElements, protyle, (e: HTMLElement) => {
e.style.fontSize = (event.target as HTMLSelectElement).value;
});
focusBlock(nodeElements[0]);
} else {
fontEvent(protyle, "fontSize", (event.target as HTMLSelectElement).value);
}
});
return element;
};
@ -164,8 +219,8 @@ export const fontEvent = (protyle: IProtyle, type?: string, color?: string) => {
setStorageVal(Constants.LOCAL_FONTSTYLES, window.siyuan.storage[Constants.LOCAL_FONTSTYLES]);
} else {
if (localFontStyles.length === 0) {
type = "color";
color = "var(--b3-font-color1)";
type = "style1";
color = "var(--b3-card-error-color)" + Constants.ZWSP + "var(--b3-card-error-background)";
} else {
const fontStyles = localFontStyles[0].split(Constants.ZWSP);
type = fontStyles[0];
@ -214,6 +269,10 @@ export const setFontStyle = (textElement: HTMLElement, textOption: ITextOption)
case "backgroundColor":
textElement.style.backgroundColor = textOption.color;
break;
case "style1":
textElement.style.backgroundColor = textOption.color.split(Constants.ZWSP)[0];
textElement.style.color = textOption.color.split(Constants.ZWSP)[1];
break;
case "style2":
textElement.style.webkitTextStroke = "0.2px var(--b3-theme-on-background)";
textElement.style.webkitTextFillColor = "transparent";
@ -304,6 +363,14 @@ export const hasSameTextStyle = (currentElement: HTMLElement, sideElement: HTMLE
fontSize === sideElement.style.fontSize &&
textObj.color === sideElement.style.backgroundColor;
}
if (textObj.type === "style1") {
return textObj.color.split(Constants.ZWSP)[0] === sideElement.style.color &&
webkitTextFillColor === sideElement.style.webkitTextFillColor &&
webkitTextStroke === sideElement.style.webkitTextStroke &&
textShadow === sideElement.style.textShadow &&
fontSize === sideElement.style.fontSize &&
textObj.color.split(Constants.ZWSP)[1] === sideElement.style.backgroundColor;
}
if (textObj.type === "style2") {
return color === sideElement.style.color &&
"transparent" === sideElement.style.webkitTextFillColor &&

View file

@ -229,8 +229,8 @@ export class Options {
tipPosition: "n",
}, {
name: "text",
lang: "font",
hotkey: window.siyuan.config.keymap.editor.insert.font.custom,
lang: "appearance",
hotkey: window.siyuan.config.keymap.editor.insert.appearance.custom,
icon: "iconFont",
tipPosition: "n",
}, {