Vanessa 2022-06-05 00:48:29 +08:00
parent 64ae905921
commit ff3cd4d4e9
21 changed files with 117 additions and 85 deletions

View file

@ -1,22 +1,29 @@
.b3-snackbar {
position: fixed;
top: 0;
z-index: 502;
transform: translate3d(0, -100px, 0);
opacity: 0;
transition: opacity 0.15s cubic-bezier(0, 0, 0.2, 1) 0ms, transform 0.15s cubic-bezier(0, 0, 0.2, 1) 0ms;
width: 100%;
align-items: center;
justify-content: center;
height: 0;
display: flex;
//transform: translate3d(0, -100px, 0);
//transition: opacity 0.15s cubic-bezier(0, 0, 0.2, 1) 0ms, transform 0.15s cubic-bezier(0, 0, 0.2, 1) 0ms;
&--show {
transform: translate3d(0, 0, 0);
opacity: 1;
margin-bottom: 16px;
position: relative;
.b3-snackbar__content {
transform: none;
&:last-child {
margin-bottom: 0;
}
&s {
position: fixed;
right: -2px;
top: 16px;
z-index: 502;
max-height: calc(100vh - 32px);
display: flex;
flex-direction: column;
& > .fn__flex-1 {
padding: 0 18px;
&::-webkit-scrollbar {
display: none;
}
}
}
@ -33,13 +40,11 @@
font-size: inherit;
background-color: var(--b3-theme-primary);
box-sizing: border-box;
box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.2), 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12);
box-shadow: 0 3px 5px -1px rgb(0 0 0 / 20%), 0 6px 10px 0 rgb(0 0 0 / 14%), 0 1px 18px 0 rgb(0 0 0 / 12%);
transition: transform 0.15s cubic-bezier(0, 0, 0.2, 1) 0ms;
transform: scale(0.8);
top: 16px;
position: absolute;
word-break: break-word;
max-width: 80vw;
width: 20vw;
min-width: 240px;
a {
color: var(--b3-theme-on-primary);
@ -54,9 +59,18 @@
&__close {
position: absolute;
cursor: pointer;
top: 8px;
right: -30px;
height: 14px;
width: 14px;
top: 10px;
right: 4px;
height: 8px;
width: 8px;
padding: 4px;
border-radius: 10px;
color: var(--b3-theme-background-light);
transition: var(--b3-transition);
&:hover {
color: var(--b3-theme-on-background);
background-color: var(--b3-theme-background-light);
}
}
}

View file

@ -22,6 +22,7 @@
<div id="dockBottom" class="dock"></div>
<div id="commonMenu" class="b3-menu fn__none"></div>
<div id="dragBg" style="z-index:199;pointer-events: none;" class="b3-dialog__scrim fn__none"></div>
<div id="message" class="b3-snackbars fn__none"></div>
<script>
setTimeout(() => {
const refreshElement = document.getElementById("loadingRefresh")

View file

@ -20,5 +20,6 @@
<div id="dockBottom" class="dock"></div>
<div id="commonMenu" class="b3-menu fn__none"></div>
<div id="dragBg" style="z-index:199;pointer-events: none;" class="b3-dialog__scrim fn__none"></div>
<div id="message" class="b3-snackbars fn__none"></div>
</body>
</html>

View file

@ -50,5 +50,6 @@
</div>
<div id="commonMenu" class="b3-menu fn__none"></div>
<div id="dragBg" style="z-index:199;pointer-events: none;" class="b3-dialog__scrim fn__none"></div>
<div id="message" class="b3-snackbars fn__none"></div>
</body>
</html>

View file

@ -299,8 +299,9 @@ ${window.siyuan.languages.account8}`;
userPassword: md5(userPasswordElement.value),
captcha: captchaElement.value.replace(/(^\s*)|(\s*$)/g, ""),
}, (data) => {
let messageId
if (data.code === 1) {
showMessage(data.msg);
messageId = showMessage(data.msg);
if (data.data.needCaptcha) {
// 验证码
needCaptcha = data.data.needCaptcha;
@ -320,7 +321,7 @@ ${window.siyuan.languages.account8}`;
token = data.data.token;
return;
}
hideMessage();
hideMessage(messageId);
fetchPost("/api/setting/getCloudUser", {
token: data.data.token,
}, response => {

View file

@ -5,7 +5,7 @@ import {SaveDialogReturnValue, shell} from "electron";
import {afterExport} from "../protyle/export/util";
/// #endif
import {isBrowser} from "../util/functions";
import {showMessage} from "../dialog/message";
import {hideMessage, showMessage} from "../dialog/message";
export const exportConfig = {
element: undefined as Element,
@ -162,10 +162,11 @@ export const exportConfig = {
properties: ["showOverwriteConfirmation"],
}).then((result: SaveDialogReturnValue) => {
if (!result.canceled) {
showMessage(window.siyuan.languages.exporting, -1);
const id = showMessage(window.siyuan.languages.exporting, -1);
fetchPost("/api/export/exportDataInFolder", {
folder: result.filePath
}, () => {
hideMessage(id)
afterExport(result.filePath);
});
}

View file

@ -160,7 +160,6 @@ export const keymap = {
item.addEventListener("keydown", function (event) {
event.stopPropagation();
event.preventDefault();
hideMessage();
let keymapStr = "";
if (event.ctrlKey && !event.metaKey && isMac()) {
keymapStr += "⌃";

View file

@ -1,41 +1,56 @@
let timeoutId: number;
export const showMessage = (message: string, timeout = 6000, type = "info") => {
clearTimeout(timeoutId);
import {genUUID} from "../util/genID";
let messageElement = document.getElementById("message");
if (!messageElement) {
document.body.insertAdjacentHTML("beforeend", '<div class="b3-snackbar" id="message"></div>');
messageElement = document.getElementById("message");
}
if (type === "error") {
messageElement.classList.add("b3-snackbar--error");
} else {
messageElement.classList.remove("b3-snackbar--error");
}
if (timeout === 0) {
messageElement.innerHTML = `<div class="b3-snackbar__content">${message}
<svg class="b3-snackbar__close fn__a"><use xlink:href="#iconClose"></use></svg></div>`;
messageElement.querySelector(".b3-snackbar__close").addEventListener("click", () => {
hideMessage();
});
} else {
messageElement.innerHTML = `<div class="b3-snackbar__content">${message}</div>`;
if (timeout !== -1) {
timeoutId = window.setTimeout(() => {
hideMessage();
}, timeout);
export const initMessage = () => {
const messageElement = document.getElementById("message")
messageElement.innerHTML = `<div class="fn__flex-1"></div>
<div class="fn__hr fn__flex-shrink"></div>
<button class="fn__flex-center b3-button b3-button--cancel">
${window.siyuan.languages.close}
</button>`
messageElement.addEventListener("click", (event) => {
let target = event.target as HTMLElement
while (target && !target.isEqualNode(messageElement)) {
if (target.classList.contains("b3-snackbar__close")) {
hideMessage(target.parentElement.getAttribute("data-id"))
event.preventDefault();
break;
} else if (target.isSameNode(messageElement.lastElementChild)) {
target.parentElement.classList.add("fn__none");
target.parentElement.innerHTML = '';
event.preventDefault();
break;
}
target = target.parentElement;
}
})
}
export const showMessage = (message: string, timeout = 6000, type = "info") => {
const id = genUUID();
let messageHTML = `<div data-id="${id}" class="b3-snackbar${type === "error" ? " b3-snackbar--error" : ""}"><div class="b3-snackbar__content">${message}</div>`;
if (timeout === 0) {
messageHTML += '<svg class="b3-snackbar__close"><use xlink:href="#iconClose"></use></svg>';
} else if (timeout !== -1) { // -1 时需等待请求完成后手动关闭
window.setTimeout(() => {
hideMessage(id);
}, timeout);
}
setTimeout(() => {
messageElement.classList.add("b3-snackbar--show");
});
const messagesElement = document.getElementById("message").firstElementChild
if (messagesElement.childElementCount === 0) {
messagesElement.parentElement.classList.remove("fn__none")
}
messagesElement.insertAdjacentHTML("afterbegin", messageHTML + "</div>");
messagesElement.scrollTop = 0;
return id;
};
export const hideMessage = () => {
const messageElement = document.getElementById("message");
export const hideMessage = (id: string) => {
const messagesElement = document.getElementById("message").firstElementChild
const messageElement = messagesElement.querySelector(`[data-id="${id}"]`);
if (messageElement) {
messageElement.innerHTML = "";
messageElement.classList.remove("b3-snackbar--show");
messageElement.remove();
}
if (messagesElement.childElementCount === 0) {
messagesElement.parentElement.classList.add("fn__none")
}
};

View file

@ -1,4 +1,4 @@
import {hideMessage, showMessage} from "../dialog/message";
import {showMessage} from "../dialog/message";
import {Dialog} from "../dialog";
import {focusByRange} from "../protyle/util/selection";
import {hasClosestBlock} from "../protyle/util/hasClosest";
@ -11,7 +11,6 @@ import {fetchPost} from "../util/fetch";
import {escapeHtml} from "../util/escape";
export const validateName = (name: string) => {
hideMessage();
if (/\r\n|\r|\n|\u2028|\u2029|\t|\//.test(name)) {
showMessage(window.siyuan.languages.fileNameRule);
return false;

View file

@ -13,6 +13,7 @@ import {repos} from "./config/repos";
import {openFileById} from "./editor/util";
import {bootSync, downloadProgress, progressLoading, setTitle, transactionError} from "./dialog/processSystem";
import {promiseTransactions} from "./protyle/wysiwyg/transaction";
import {initMessage, showMessage} from "./dialog/message";
class App {
constructor() {
@ -87,6 +88,7 @@ class App {
dragElement.style.paddingRight = (dragElement.getBoundingClientRect().left - document.querySelector("#windowControls").clientWidth) + "px";
}
setTitle(window.siyuan.languages.siyuanNote);
initMessage();
});
});
});

View file

@ -602,7 +602,6 @@ export class Files extends Model {
}
private onMount(data: { data: { box: INotebook, existed?: boolean }, callback?: string }) {
hideMessage();
if (data.data.existed) {
return;
}

View file

@ -639,11 +639,11 @@ export const exportMd = (id: string) => {
label: "Markdown",
icon: "iconMarkdown",
click: () => {
showMessage(window.siyuan.languages.exporting, -1);
const id = showMessage(window.siyuan.languages.exporting, -1);
fetchPost("/api/export/exportMd", {
id,
}, response => {
hideMessage();
hideMessage(id);
if (window.siyuan.config.system.container === "ios") {
window.location.href = response.data.zip;
} else if (window.siyuan.config.system.container === "android" && window.JSAndroid) {
@ -658,11 +658,11 @@ export const exportMd = (id: string) => {
label: "SiYuan .sy.zip",
icon: "iconSiYuan",
click: () => {
showMessage(window.siyuan.languages.exporting, -1);
const id = showMessage(window.siyuan.languages.exporting, -1);
fetchPost("/api/export/exportSY", {
id,
}, response => {
hideMessage();
hideMessage(id);
if (window.siyuan.config.system.container === "ios") {
window.location.href = response.data.zip;
} else if (window.siyuan.config.system.container === "android" && window.JSAndroid) {

View file

@ -108,12 +108,12 @@ export const initNavigationMenu = (liElement: HTMLElement) => {
label: window.siyuan.languages.export,
icon: "iconUpload",
click: () => {
showMessage(window.siyuan.languages.exporting, -1);
const id = showMessage(window.siyuan.languages.exporting, -1);
fetchPost("/api/export/batchExportMd", {
notebook: notebookId,
path: "/"
}, response => {
hideMessage();
hideMessage(id);
window.open(response.data.zip);
});
}

View file

@ -14,6 +14,7 @@ import {initAssets, loadAssets} from "../util/assets";
import {openMobileFileById} from "./editor";
import {promiseTransactions} from "../protyle/wysiwyg/transaction";
import {bootSync} from "../dialog/processSystem";
import {initMessage} from "../dialog/message";
class App {
constructor() {
@ -58,6 +59,7 @@ class App {
} else if (window.siyuan.config.system.container === "android" && window.JSAndroid) {
window.JSAndroid.changeStatusBarColor(getComputedStyle(document.body).getPropertyValue("--b3-theme-background"), window.siyuan.config.appearance.mode);
}
initMessage();
});
});
if (navigator.userAgent.indexOf("iPhone") > -1) {

View file

@ -496,7 +496,6 @@ export class MobileFiles extends Model {
}
private onMount(data: { data: { box: INotebook, existed?: boolean }, callback?: string }) {
hideMessage();
if (data.data.existed) {
return;
}

View file

@ -166,6 +166,7 @@ export class Breadcrumb {
icon: "iconRecord",
label: this.mediaRecorder?.isRecording ? window.siyuan.languages.endRecord : window.siyuan.languages.startRecord,
click: () => {
let messageId = ''
if (!this.mediaRecorder) {
navigator.mediaDevices.getUserMedia({audio: true}).then((mediaStream: MediaStream) => {
this.mediaRecorder = new RecordMedia(mediaStream);
@ -180,7 +181,7 @@ export class Breadcrumb {
this.mediaRecorder.cloneChannelData(left, right);
};
this.mediaRecorder.startRecordingNewWavFile();
showMessage(window.siyuan.languages.recording, 86400000);
id = showMessage(window.siyuan.languages.recording, -1);
}).catch(() => {
showMessage(window.siyuan.languages["record-tip"]);
});
@ -189,12 +190,13 @@ export class Breadcrumb {
if (this.mediaRecorder.isRecording) {
this.mediaRecorder.stopRecording();
hideMessage();
hideMessage(messageId);
const file: File = new File([this.mediaRecorder.buildWavFileBlob()],
`record${(new Date()).getTime()}.wav`, {type: "video/webm"});
uploadFiles(protyle, [file]);
} else {
showMessage(window.siyuan.languages.recording, 86400000);
hideMessage(messageId);
messageId = showMessage(window.siyuan.languages.recording, -1);
this.mediaRecorder.startRecordingNewWavFile();
}
}

View file

@ -1,4 +1,4 @@
import {showMessage} from "../../dialog/message";
import {hideMessage, showMessage} from "../../dialog/message";
import {Constants} from "../../constants";
/// #if !BROWSER
import {PrintToPDFOptions, SaveDialogReturnValue} from "electron";
@ -126,7 +126,7 @@ const getExportPath = (option: { type: string, id: string }, pdfOption?: PrintTo
properties: ["showOverwriteConfirmation"],
}).then((result: SaveDialogReturnValue) => {
if (!result.canceled) {
showMessage(window.siyuan.languages.exporting, -1);
const id = showMessage(window.siyuan.languages.exporting, -1);
let url = "/api/export/exportHTML";
if (option.type === "htmlmd") {
url = "/api/export/exportMdHTML";
@ -138,6 +138,7 @@ const getExportPath = (option: { type: string, id: string }, pdfOption?: PrintTo
pdf: option.type === "pdf",
savePath: result.filePath
}, exportResponse => {
hideMessage(id);
if (option.type === "word") {
afterExport(result.filePath);
} else {

View file

@ -5,7 +5,7 @@ import {shell} from "electron";
import * as path from "path";
export const afterExport = (exportPath: string) => {
showMessage(`<div class="fn__flex">
const id = showMessage(`<div class="fn__flex">
<div class="fn__flex-center">${window.siyuan.languages.exported}${escapeHtml(exportPath)}</div>
<div class="fn__space"></div>
<div class="fn__space"></div>
@ -13,7 +13,7 @@ export const afterExport = (exportPath: string) => {
</div>`, 6000);
document.querySelector("#message button").addEventListener("click", () => {
shell.showItemInFolder(path.join(exportPath));
hideMessage();
hideMessage(id);
});
};
/// #endif

View file

@ -81,7 +81,6 @@ export class Background {
uploadFiles(protyle, event.target.files, event.target, (responseText) => {
const response = JSON.parse(responseText);
const style = `background-image:url(${response.data.succMap[Object.keys(response.data.succMap)[0]]})`;
hideMessage();
this.ial["title-img"] = Lute.EscapeHTMLStr(style);
this.render(this.ial, protyle.block.rootID);
fetchPost("/api/attr/setBlockAttrs", {

View file

@ -17,7 +17,6 @@ export class Upload {
}
const validateFile = (protyle: IProtyle, files: File[]) => {
hideMessage();
const uploadFileList = [];
let errorTip = "";
let uploadingStr = "";
@ -94,8 +93,6 @@ const genUploadedLabel = (responseText: string, protyle: IProtyle) => {
if (errorTip) {
showMessage(errorTip);
} else {
hideMessage();
}
let succFileText = "";

View file

@ -8,7 +8,6 @@ export const processMessage = (response: IWebSocketData) => {
return false;
}
if ("cmsg" === response.cmd) {
hideMessage();
const progressElement = document.getElementById("progress");
if (progressElement) {
progressElement.remove();