diff --git a/app/appearance/langs/en_US.json b/app/appearance/langs/en_US.json
index 91b3c10f0..29d95128a 100644
--- a/app/appearance/langs/en_US.json
+++ b/app/appearance/langs/en_US.json
@@ -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 workspace/data/ 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",
diff --git a/app/appearance/langs/es_ES.json b/app/appearance/langs/es_ES.json
index 4b80d9b8c..23cd0e9a6 100644
--- a/app/appearance/langs/es_ES.json
+++ b/app/appearance/langs/es_ES.json
@@ -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 workspace/data/ 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",
diff --git a/app/appearance/langs/fr_FR.json b/app/appearance/langs/fr_FR.json
index 87f692b0f..5158b9b66 100644
--- a/app/appearance/langs/fr_FR.json
+++ b/app/appearance/langs/fr_FR.json
@@ -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 workspace/data/ 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",
diff --git a/app/appearance/langs/zh_CHT.json b/app/appearance/langs/zh_CHT.json
index d04bc1d88..3500b09c1 100644
--- a/app/appearance/langs/zh_CHT.json
+++ b/app/appearance/langs/zh_CHT.json
@@ -1,4 +1,5 @@
{
+ "color": "顏色",
"confirmPassword": "我已經牢記密碼了",
"passwordNoMatch": "兩次輸入的密碼不一致",
"cloudConfigTip": "請在 [設置 - 雲端] 中進行配置",
@@ -247,7 +248,7 @@
"importDataTip": "將導出的 zip 壓縮包導入,按路徑覆蓋 工作空間/data/ 文件夾",
"includeChildDoc": "包含子文檔",
"text": "文字",
- "lastUsed": "最近使用過的字體",
+ "lastUsed": "最近使用過的外觀",
"removedNotebook": "已刪除的筆記本",
"querySyntax": "查詢語法",
"rollback": "回滾",
diff --git a/app/appearance/langs/zh_CN.json b/app/appearance/langs/zh_CN.json
index a71c5a452..fb8a1a0a4 100644
--- a/app/appearance/langs/zh_CN.json
+++ b/app/appearance/langs/zh_CN.json
@@ -1,4 +1,5 @@
{
+ "color": "颜色",
"confirmPassword": "我已经牢记密码了",
"passwordNoMatch": "两次输入的密码不一致",
"cloudConfigTip": "请在 [设置 - 云端] 中进行配置",
@@ -247,7 +248,7 @@
"importDataTip": "将导出的 zip 压缩包导入,按路径覆盖 工作空间/data/ 文件夹",
"includeChildDoc": "包含子文档",
"text": "文本",
- "lastUsed": "最近使用过的字体",
+ "lastUsed": "最近使用过的外观",
"removedNotebook": "已删除的笔记本",
"querySyntax": "查询语法",
"rollback": "回滚",
diff --git a/app/src/constants.ts b/app/src/constants.ts
index 8a0ec171c..eb148338e 100644
--- a/app/src/constants.ts
+++ b/app/src/constants.ts
@@ -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: "⌘'"},
diff --git a/app/src/protyle/gutter/index.ts b/app/src/protyle/gutter/index.ts
index 7d4637a24..cb0586af1 100644
--- a/app/src/protyle/gutter/index.ts
+++ b/app/src/protyle/gutter/index.ts
@@ -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 ? `` : Constants.ZWSP,
- label: isM ? `${window.siyuan.languages.colorPrimary} ${index + 1}` : `
-
-
`,
- click: () => {
- this.genClick(nodeElements, protyle, (e: HTMLElement) => {
- e.style.backgroundColor = item;
- });
- }
- });
- });
- styles.push({
- type: "separator"
- });
- styles.push({
- iconHTML: isM ? 'A' : Constants.ZWSP,
- label: isM ? window.siyuan.languages.clearFontStyle : `
- A
-
`,
- 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 ? `A` : Constants.ZWSP,
- label: isM ? `${window.siyuan.languages.colorFont} ${index + 1}` : `
- A
-
`,
- 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 ? `A` : Constants.ZWSP,
- label: isM ? window.siyuan.languages[item + "Style"] : `
- A
-
`,
- 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 ? 'A' : Constants.ZWSP,
- label: isM ? window.siyuan.languages.hollow : `
- A
-
`,
- click: () => {
- this.genClick(nodeElements, protyle, (e: HTMLElement) => {
- e.style.webkitTextStroke = "0.2px var(--b3-theme-on-background)";
- e.style.webkitTextFillColor = "transparent";
- });
- }
- }, {
- iconHTML: isM ? ' A' : Constants.ZWSP,
- label: isM ? window.siyuan.languages.shadow : `
- A
-
`,
- 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;
diff --git a/app/src/protyle/toolbar/Font.ts b/app/src/protyle/toolbar/Font.ts
index 10b393747..783929be8 100644
--- a/app/src/protyle/toolbar/Font.ts
+++ b/app/src/protyle/toolbar/Font.ts
@@ -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 += ``;
break;
+ case "style1":
+ lastColorHTML += ``;
+ break;
}
});
lastColorHTML += "";
}
- 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}
+${window.siyuan.languages.color}
+
+
+
+
+
+
+
+
${window.siyuan.languages.colorFont}
@@ -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 &&
diff --git a/app/src/protyle/util/Options.ts b/app/src/protyle/util/Options.ts
index 0147e8c28..23c803e95 100644
--- a/app/src/protyle/util/Options.ts
+++ b/app/src/protyle/util/Options.ts
@@ -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",
}, {