A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)

Remove Account Login from UI

Remove account login from the UI but not from the kernel. Also
this intentionally does not enable paid-for features.

Signed-off-by: Jacob Abel <jacobabel@nullpo.dev>

+2 -1080
-85
app/src/assets/scss/business/_config.scss
··· 93 93 } 94 94 } 95 95 96 - &-account { 97 - height: 100%; 98 - 99 - &__center { 100 - flex-direction: column; 101 - justify-content: center; 102 - flex: 1; 103 - display: flex; 104 - min-width: 1px; 105 - align-items: center; 106 - 107 - &--text { 108 - background-color: var(--b3-theme-surface); 109 - padding: 16px 24px; 110 - overflow: auto; 111 - 112 - .b3-button--outline { 113 - white-space: normal; 114 - } 115 - } 116 - } 117 - 118 - &__form { 119 - max-width: 298px; 120 - width: 100%; 121 - } 122 - 123 - &__bg { 124 - position: relative; 125 - margin-bottom: 82px; 126 - width: 100%; 127 - flex: 1; 128 - min-height: 128px; 129 - } 130 - 131 - &__info { 132 - width: 100%; 133 - box-sizing: border-box; 134 - padding: 16px 24px; 135 - margin-top: 10vh; 136 - } 137 - 138 - &__cover { 139 - position: absolute; 140 - top: 0; 141 - width: 100%; 142 - height: 100%; 143 - background-size: cover; 144 - background-position: center center; 145 - } 146 - 147 - &__avatar { 148 - position: absolute; 149 - bottom: 24px; 150 - width: 128px; 151 - height: 128px; 152 - left: 50%; 153 - margin-left: -64px; 154 - background-repeat: no-repeat; 155 - background-position: 50%; 156 - background-size: cover; 157 - border-radius: 90px; 158 - background-color: rgba(255, 255, 255, .8); 159 - box-shadow: var(--b3-point-shadow); 160 - border: 1px solid var(--b3-theme-surface-lighter); 161 - } 162 - 163 - &__name { 164 - bottom: -58px; 165 - position: absolute; 166 - width: 100%; 167 - text-align: center; 168 - } 169 - 170 - &__svg { 171 - flex-wrap: wrap; 172 - 173 - svg { 174 - margin: 8px; 175 - height: 16px; 176 - width: 16px; 177 - } 178 - } 179 - } 180 - 181 96 &-about__logo { 182 97 display: flex; 183 98 align-items: center;
-42
app/src/assets/scss/mobile.scss
··· 213 213 } 214 214 } 215 215 216 - .config-account { 217 - &__bg { 218 - position: relative; 219 - width: 100%; 220 - flex: 1; 221 - } 222 - 223 - &__cover { 224 - width: 100vw; 225 - height: 50vh; 226 - background-size: cover; 227 - background-position: center center; 228 - } 229 - 230 - &__avatar { 231 - position: absolute; 232 - top: 50vh; 233 - width: 128px; 234 - height: 128px; 235 - left: 50%; 236 - margin: -160px 0 0 -64px; 237 - background-repeat: no-repeat; 238 - background-position: 50%; 239 - background-size: cover; 240 - border-radius: 90px; 241 - background-color: rgba(255, 255, 255, .8); 242 - box-shadow: var(--b3-point-shadow); 243 - border: 1px solid var(--b3-theme-surface-lighter); 244 - } 245 - 246 - &__info { 247 - width: 100%; 248 - box-sizing: border-box; 249 - padding: 16px; 250 - } 251 - 252 - &__name { 253 - width: 100%; 254 - text-align: center; 255 - } 256 - } 257 - 258 216 .config-assets { 259 217 display: flex; 260 218 flex-direction: column;
-4
app/src/assets/scss/util/_responsive.scss
··· 27 27 margin-top: 8px; 28 28 } 29 29 30 - .config-account { 31 - flex-direction: column; 32 - min-height: 100%; 33 - } 34 30 } 35 31 36 32 &__item {
-511
app/src/config/account.ts
··· 1 - import * as md5 from "blueimp-md5"; 2 - import {hideMessage, showMessage} from "../dialog/message"; 3 - import {Constants} from "../constants"; 4 - import {fetchPost} from "../util/fetch"; 5 - import {repos} from "./repos"; 6 - import {confirmDialog} from "../dialog/confirmDialog"; 7 - import {hasClosestByClassName} from "../protyle/util/hasClosest"; 8 - import {getEventName, isInIOS} from "../protyle/util/compatibility"; 9 - import {processSync} from "../dialog/processSystem"; 10 - import {needSubscribe} from "../util/needSubscribe"; 11 - import {syncGuide} from "../sync/syncGuide"; 12 - import {hideElements} from "../protyle/ui/hideElements"; 13 - import {getCloudURL, getIndexURL} from "./util/about"; 14 - import {iOSPurchase} from "../util/iOSPurchase"; 15 - 16 - const genSVGBG = () => { 17 - let html = ""; 18 - const svgs: string[] = []; 19 - document.querySelectorAll("body > svg > defs > symbol").forEach((item) => { 20 - svgs.push(item.id); 21 - }); 22 - Array.from({length: 45}, () => { 23 - const index = Math.floor(Math.random() * svgs.length); 24 - html += `<svg><use xlink:href="#${svgs[index]}"></use></svg>`; 25 - svgs.splice(index, 1); 26 - }); 27 - return `<div class="fn__flex config-account__svg">${html}</div>`; 28 - }; 29 - 30 - export const account = { 31 - element: undefined as Element, 32 - genHTML: (onlyPayHTML = false) => { 33 - const isIOS = isInIOS(); 34 - let payHTML; 35 - if (isIOS) { 36 - // 已付费 37 - if (window.siyuan.user?.userSiYuanOneTimePayStatus === 1) { 38 - payHTML = `<button class="b3-button b3-button--big" data-action="iOSPay" data-type="subscribe"> 39 - <svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.account4} 40 - </button>`; 41 - } else { 42 - payHTML = `<button class="b3-button b3-button--big" data-action="iOSPay" data-type="subscribe"> 43 - <svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.account10} 44 - </button> 45 - <div class="fn__hr"></div> 46 - <button class="b3-button b3-button--success" data-action="iOSPay" data-type="function"> 47 - <svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.onepay} 48 - </button>`; 49 - } 50 - } else { 51 - payHTML = `<a class="b3-button b3-button--big" href="${getIndexURL("pricing.html")}" target="_blank"> 52 - <svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages[window.siyuan.user?.userSiYuanOneTimePayStatus === 1 ? "account4" : "account1"]} 53 - </a>`; 54 - } 55 - payHTML += `<div class="fn__hr--b"></div> 56 - <span class="b3-chip b3-chip--primary b3-chip--hover${(window.siyuan.user && window.siyuan.user.userSiYuanSubscriptionStatus === 2) ? " fn__none" : ""}" id="trialSub"> 57 - <svg class="ft__secondary"><use xlink:href="#iconVIP"></use></svg> 58 - ${window.siyuan.languages.freeSub} 59 - </span> 60 - <div class="fn__hr${(window.siyuan.user && window.siyuan.user.userSiYuanSubscriptionStatus === 2) ? " fn__none" : ""}"></div> 61 - <a href="${getCloudURL("sponsor")}" target="_blank" class="${isIOS ? "fn__none " : ""}b3-chip b3-chip--pink b3-chip--hover"> 62 - <svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'><path fill='#ffe43c' d='M6.4 0h19.2c4.268 0 6.4 2.132 6.4 6.4v19.2c0 4.268-2.132 6.4-6.4 6.4h-19.2c-4.268 0-6.4-2.132-6.4-6.4v-19.2c0-4.268 2.135-6.4 6.4-6.4z'></path> <path fill='#00f5d4' d='M25.6 0h-8.903c-7.762 1.894-14.043 7.579-16.697 15.113v10.487c0 3.533 2.867 6.4 6.4 6.4h19.2c3.533 0 6.4-2.867 6.4-6.4v-19.2c0-3.537-2.863-6.4-6.4-6.4z'></path> <path fill='#01beff' d='M25.6 0h-0.119c-12.739 2.754-20.833 15.316-18.079 28.054 0.293 1.35 0.702 2.667 1.224 3.946h16.974c3.533 0 6.4-2.867 6.4-6.4v-19.2c0-3.537-2.863-6.4-6.4-6.4z'></path> <path fill='#9a5ce5' d='M31.005 2.966c-0.457-0.722-1.060-1.353-1.784-1.849-8.342 3.865-13.683 12.223-13.679 21.416-0.003 3.256 0.67 6.481 1.978 9.463h8.081c0.602 0 1.185-0.084 1.736-0.238-2.1-3.189-3.401-7.624-3.401-12.526 0-7.337 2.921-13.628 7.070-16.266z'></path> <path fill='#f15bb5' d='M32 25.6v-19.2c0-1.234-0.354-2.419-0.998-3.43-4.149 2.638-7.067 8.928-7.067 16.266 0 4.902 1.301 9.334 3.401 12.526 2.693-0.757 4.664-3.231 4.664-6.162z'></path> <path fill='#fff' opacity='0.2' d='M26.972 22.415c-2.889 0.815-4.297 2.21-6.281 3.182 1.552 0.348 3.105 0.461 4.902 0.461 2.644 0 5.363-1.449 6.406-2.519v-1.085c-1.598-0.399-2.664-0.705-5.028-0.039zM4.773 21.612c-0.003 0-0.006-0.003-0.006-0.003-1.726-0.863-3.382-1.205-4.767-1.301v2.487c0.779-0.341 2.396-0.921 4.773-1.182zM17.158 26.599c1.472-0.158 2.57-0.531 3.533-1.002-1.063-0.238-2.126-0.583-3.269-1.079-2.767-1.205-5.63-3.092-10.491-3.034-0.779 0.010-1.495 0.058-2.158 0.132 4.503 2.248 7.882 5.463 12.384 4.983z'></path> <path fill='#fff' opacity='0.2' d='M20.691 25.594c-0.963 0.47-2.061 0.844-3.533 1.002-4.503 0.483-7.882-2.731-12.381-4.983-2.38 0.261-3.994 0.841-4.773 1.179v2.809c0 4.268 2.132 6.4 6.4 6.4h19.197c4.268 0 6.4-2.132 6.4-6.4v-2.065c-1.044 1.069-3.762 2.519-6.406 2.519-1.797 0-3.35-0.113-4.902-0.461z'></path> <path fill='#fff' opacity='0.5' d='M3.479 19.123c0 0.334 0.271 0.606 0.606 0.606s0.606-0.271 0.606-0.606v0c0-0.334-0.271-0.606-0.606-0.606s-0.606 0.271-0.606 0.606v0z'></path> <path fill='#fff' opacity='0.5' d='M29.027 14.266c0 0.334 0.271 0.606 0.606 0.606s0.606-0.271 0.606-0.606v0c0-0.334-0.271-0.606-0.606-0.606s-0.606 0.271-0.606 0.606v0z'></path> <path fill='#fff' d='M9.904 1.688c0 0.167 0.136 0.303 0.303 0.303s0.303-0.136 0.303-0.303v0c0-0.167-0.136-0.303-0.303-0.303s-0.303 0.136-0.303 0.303v0z'></path> <path fill='#fff' d='M2.673 10.468c0 0.167 0.136 0.303 0.303 0.303s0.303-0.136 0.303-0.303v0c0-0.167-0.136-0.303-0.303-0.303s-0.303 0.136-0.303 0.303v0z'></path> <path fill='#fff' opacity='0.6' d='M30.702 9.376c0 0.167 0.136 0.303 0.303 0.303s0.303-0.136 0.303-0.303v0c0-0.167-0.136-0.303-0.303-0.303s-0.303 0.136-0.303 0.303v0z'></path> <path fill='#fff' opacity='0.8' d='M29.236 20.881c0 0.276 0.224 0.499 0.499 0.499s0.499-0.224 0.499-0.499v0c0-0.276-0.224-0.499-0.499-0.499s-0.499 0.224-0.499 0.499v0z'></path> <path fill='#fff' opacity='0.8' d='M15.38 1.591c0.047 0.016 0.101 0.026 0.158 0.026 0.276 0 0.499-0.224 0.499-0.499 0-0.219-0.141-0.406-0.338-0.473l-0.004-0.001c-0.047-0.016-0.101-0.026-0.158-0.026-0.276 0-0.499 0.224-0.499 0.499 0 0.219 0.141 0.406 0.338 0.473l0.004 0.001z'></path> <path fill='#ffdeeb' d='M25.732 8.268c-2.393-2.371-6.249-2.371-8.642 0l-1.089 1.085-1.079-1.089c-2.38-2.39-6.249-2.393-8.639-0.013s-2.393 6.249-0.013 8.639l2.158 2.158 6.474 6.464c0.596 0.593 1.562 0.593 2.158 0l6.474-6.464 2.193-2.158c2.384-2.383 2.384-6.242 0.003-8.622z'></path> <path fill='#fff' d='M17.081 8.268l-1.079 1.085-1.079-1.089c-2.38-2.39-6.249-2.393-8.639-0.013s-2.393 6.249-0.013 8.639l2.158 2.158 2.548 2.487c4.097-1.044 7.627-3.646 9.837-7.254 1.424-2.271 2.284-4.848 2.503-7.518-2.193-0.715-4.606-0.132-6.236 1.504z'></path> </svg> 63 - ${window.siyuan.languages.sponsor} 64 - </a> 65 - <div class="fn__hr--b"></div> 66 - <div class="fn__flex-1"></div> 67 - <div> 68 - ${window.siyuan.languages.accountSupport1} 69 - </div> 70 - <div class="fn__hr--b"></div> 71 - <div> 72 - ${window.siyuan.languages.accountSupport2} 73 - </div>`; 74 - if (onlyPayHTML) { 75 - return `<div class="fn__flex-1 fn__hr--b"></div> 76 - ${genSVGBG()} 77 - <div class="fn__flex-1 fn__hr--b"></div> 78 - ${payHTML} 79 - <div class="fn__flex-1 fn__hr--b"></div> 80 - ${genSVGBG()} 81 - <div class="fn__flex-1 fn__hr--b"></div>`; 82 - } 83 - if (window.siyuan.user) { 84 - let userTitlesHTML = ""; 85 - if (window.siyuan.user.userTitles.length > 0) { 86 - userTitlesHTML = '<div class="b3-chips" style="position: absolute">'; 87 - window.siyuan.user.userTitles.forEach((item) => { 88 - userTitlesHTML += `<div class="b3-chip b3-chip--middle b3-chip--primary">${item.icon} ${item.name}</div>`; 89 - }); 90 - userTitlesHTML += "</div>"; 91 - } 92 - let subscriptionHTML = ""; 93 - let activeSubscriptionHTML = isIOS ? "" : `<div class="b3-form__icon fn__block"> 94 - <svg class="ft__secondary b3-form__icon-icon"><use xlink:href="#iconVIP"></use></svg> 95 - <input class="b3-text-field fn__block b3-form__icon-input" style="padding-right: 44px;" placeholder="${window.siyuan.languages.activationCodePlaceholder}"> 96 - <button id="activationCode" class="b3-button b3-button--text" style="position: absolute;right: 0;top: 0;">${window.siyuan.languages.confirm}</button> 97 - </div>`; 98 - if (window.siyuan.user.userSiYuanProExpireTime === -1) { 99 - // 终身会员 100 - activeSubscriptionHTML = ""; 101 - subscriptionHTML = `<div class="b3-chip b3-chip--secondary">${Constants.SIYUAN_IMAGE_VIP}${window.siyuan.languages.account12}</div>`; 102 - } else if (window.siyuan.user.userSiYuanProExpireTime > 0) { 103 - // 订阅中 104 - const renewHTML = `<div class="fn__hr--b"></div> 105 - <div class="ft__on-surface ft__smaller"> 106 - ${window.siyuan.languages.account6} 107 - ${Math.max(0, Math.floor((window.siyuan.user.userSiYuanProExpireTime - new Date().getTime()) / 1000 / 60 / 60 / 24))} 108 - ${window.siyuan.languages.day} 109 - ${isIOS ? `<a href="javascript:void(0)" data-action="iOSPay" data-type="subscribe">${window.siyuan.languages.clickMeToRenew}</a>` : `<a href="${getCloudURL("subscribe/siyuan")}" target="_blank">${window.siyuan.languages.clickMeToRenew}</a>`} 110 - </div>`; 111 - if (window.siyuan.user.userSiYuanOneTimePayStatus === 1) { 112 - subscriptionHTML = `<div class="b3-chip b3-chip--success"><svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.account7}</div> 113 - <div class="fn__hr--b"></div>`; 114 - } 115 - if (window.siyuan.user.userSiYuanSubscriptionPlan === 2) { 116 - // 订阅试用 117 - subscriptionHTML += `<div class="b3-chip b3-chip--primary"><svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.account3}</div> 118 - ${renewHTML}<div class="fn__hr--b"></div>`; 119 - } else { 120 - // 年费 121 - subscriptionHTML += `<div class="b3-chip b3-chip--primary"><svg class="ft__secondary"><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.account8}</div> 122 - ${renewHTML}<div class="fn__hr--b"></div>`; 123 - } 124 - if (window.siyuan.user.userSiYuanOneTimePayStatus === 0) { 125 - subscriptionHTML += isIOS ? `<button class="b3-button b3-button--success" data-action="iOSPay" data-type="function"> 126 - <svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.onepay} 127 - </button>` : `<a class="b3-button b3-button--success" href="${getIndexURL("pricing.html")}" target="_blank"> 128 - <svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.onepay} 129 - </a>`; 130 - } 131 - } else { 132 - if (window.siyuan.user.userSiYuanOneTimePayStatus === 1) { 133 - subscriptionHTML = `<div class="b3-chip b3-chip--success"><svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.account7}</div> 134 - <div class="fn__hr--b"></div>${payHTML}`; 135 - } else { 136 - subscriptionHTML = payHTML; 137 - } 138 - } 139 - return `<div class="fn__flex config-account"> 140 - <div class="config-account__center"> 141 - <div class="config-account__bg"> 142 - <div class="config-account__cover" style="background-image: url(${window.siyuan.user.userHomeBImgURL})"></div> 143 - <a href="${getCloudURL("settings/avatar")}" class="config-account__avatar" style="background-image: url(${window.siyuan.user.userAvatarURL})" target="_blank"></a> 144 - <h1 class="config-account__name"> 145 - <a target="_blank" class="fn__a" href="${getCloudURL("member/" + window.siyuan.user.userName)}">${window.siyuan.user.userName}</a> 146 - <span class="ft__on-surface ft__smaller">${0 === window.siyuan.config.cloudRegion ? "ld246.com" : "liuyun.io"}</span> 147 - </h1> 148 - ${userTitlesHTML} 149 - </div> 150 - <div class="config-account__info"> 151 - <div class="fn__flex"> 152 - <a class="b3-button b3-button--text${isIOS ? " fn__none" : ""}" href="${getCloudURL("settings")}" target="_blank">${window.siyuan.languages.manage}</a> 153 - <span class="fn__space${isIOS ? " fn__none" : ""}"></span> 154 - <button class="b3-button b3-button--cancel" id="logout"> 155 - ${window.siyuan.languages.logout} 156 - </button> 157 - <span class="fn__space"></span> 158 - <button class="b3-button b3-button--cancel${window.siyuan.config.system.container === "ios" ? "" : " fn__none"}" id="deactivateUser"> 159 - ${window.siyuan.languages.deactivateUser} 160 - </button> 161 - <span class="fn__flex-1"></span> 162 - <button class="b3-button b3-button--cancel b3-tooltips b3-tooltips__n" id="refresh" aria-label="${window.siyuan.languages.refresh}"> 163 - <svg style="margin-right: 0"><use xlink:href="#iconRefresh"></use></svg> 164 - </button> 165 - </div> 166 - <div class="fn__hr--b"></div> 167 - <div class="fn__flex"> 168 - <label> 169 - ${window.siyuan.languages.accountDisplayTitle} 170 - <input class="b3-switch fn__flex-center" id="displayTitle" type="checkbox"${window.siyuan.config.account.displayTitle ? " checked" : ""}/> 171 - </label> 172 - <div class="fn__flex-1"></div> 173 - <label> 174 - ${window.siyuan.languages.accountDisplayVIP} 175 - <input class="b3-switch fn__flex-center" id="displayVIP" type="checkbox"${window.siyuan.config.account.displayVIP ? " checked" : ""}/> 176 - </label> 177 - </div> 178 - </div> 179 - </div> 180 - <div class="config-account__center config-account__center--text"> 181 - <div class="fn__flex-1 fn__hr--b"></div> 182 - ${subscriptionHTML} 183 - <div class="fn__flex-1 fn__hr--b"></div> 184 - ${activeSubscriptionHTML} 185 - </div></div>`; 186 - } 187 - return `<div class="fn__flex config-account"> 188 - <div class="b3-form__space config-account__center"> 189 - <div class="config-account__form" id="form1"> 190 - <div class="b3-form__icon"> 191 - <svg class="b3-form__icon-icon"><use xlink:href="#iconAccount"></use></svg> 192 - <input id="userName" class="b3-text-field fn__block b3-form__icon-input" placeholder="${window.siyuan.languages.accountName}"> 193 - </div> 194 - <div class="fn__hr--b"></div> 195 - <div class="b3-form__icon"> 196 - <svg class="b3-form__icon-icon"><use xlink:href="#iconLock"></use></svg> 197 - <input type="password" id="userPassword" class="b3-text-field b3-form__icon-input fn__block" placeholder="${window.siyuan.languages.password}"> 198 - </div> 199 - <div class="fn__hr--b"></div> 200 - <div class="b3-form__icon"> 201 - <svg class="b3-form__icon-icon"><use xlink:href="#iconFocus"></use></svg> 202 - <select class="b3-select b3-form__icon-input fn__block" id="cloudRegion"> 203 - <option value="0"${window.siyuan.config.cloudRegion === 0 ? " selected" : ""}>${window.siyuan.languages.cloudRegionChina}</option> 204 - <option value="1"${window.siyuan.config.cloudRegion === 1 ? " selected" : ""}>${window.siyuan.languages.cloudRegionNorthAmerica}</option> 205 - </select> 206 - </div> 207 - <div class="b3-form__img fn__none"> 208 - <div class="fn__hr--b"></div> 209 - <img id="captchaImg" class="fn__pointer" style="top: 17px;height:26px"> 210 - <input id="captcha" class="b3-text-field fn__block" placeholder="${window.siyuan.languages.captcha}"> 211 - </div> 212 - <div class="fn__hr--b"></div> 213 - <label class="ft__smaller ft__on-surface fn__flex"> 214 - <span class="fn__space"></span> 215 - <input type="checkbox" class="b3-switch fn__flex-center" id="agreeLogin"> 216 - <span class="fn__space"></span> 217 - <span>${window.siyuan.languages.accountTip}</span> 218 - </label> 219 - <div class="fn__hr--b"></div> 220 - <button id="login" disabled class="b3-button fn__block">${window.siyuan.languages.login}</button> 221 - <div class="fn__hr--b"></div> 222 - <div class="ft__center"> 223 - <a href="${getCloudURL("forget-pwd")}" class="b3-button b3-button--cancel" target="_blank">${window.siyuan.languages.forgetPassword}</a> 224 - <span class="fn__space${window.siyuan.config.system.container === "ios" ? " fn__none" : ""}"></span> 225 - <a href="${getCloudURL("register")}" class="b3-button b3-button--cancel${window.siyuan.config.system.container === "ios" ? " fn__none" : ""}" target="_blank">${window.siyuan.languages.register}</a> 226 - </div> 227 - </div> 228 - <div class="fn__none config-account__form" id="form2"> 229 - <div class="b3-form__icon"> 230 - <svg class="b3-form__icon-icon"><use xlink:href="#iconLock"></use></svg> 231 - <input id="twofactorAuthCode" class="b3-text-field fn__block b3-form__icon-input" placeholder="${window.siyuan.languages.twoFactorCaptcha}"> 232 - </div> 233 - <div class="fn__hr--b"></div> 234 - <button id="login2" class="b3-button fn__block">${window.siyuan.languages.login}</button> 235 - </div> 236 - </div> 237 - <div class="config-account__center config-account__center--text${window.siyuan.config.system.container === "ios" ? " fn__none" : ""}"> 238 - <div class="fn__flex-1 fn__hr--b"></div> 239 - ${genSVGBG()} 240 - <div class="fn__flex-1 fn__hr--b"></div> 241 - ${payHTML} 242 - <div class="fn__flex-1 fn__hr--b"></div> 243 - ${genSVGBG()} 244 - <div class="fn__flex-1 fn__hr--b"></div> 245 - </div> 246 - </div>`; 247 - }, 248 - bindEvent: (element: Element) => { 249 - element.querySelectorAll('[data-action="iOSPay"]').forEach(item => { 250 - item.addEventListener("click", () => { 251 - iOSPurchase(item.getAttribute("data-type")); 252 - }); 253 - }); 254 - const trialSubElement = element.querySelector("#trialSub"); 255 - if (trialSubElement) { 256 - trialSubElement.addEventListener("click", () => { 257 - fetchPost("/api/account/startFreeTrial", {}, () => { 258 - element.querySelector("#refresh").dispatchEvent(new Event("click")); 259 - }); 260 - }); 261 - } 262 - const agreeLoginElement = element.querySelector("#agreeLogin") as HTMLInputElement; 263 - const userNameElement = element.querySelector("#userName") as HTMLInputElement; 264 - if (!userNameElement) { 265 - const refreshElement = element.querySelector("#refresh"); 266 - refreshElement.addEventListener("click", () => { 267 - const svgElement = refreshElement.firstElementChild; 268 - if (svgElement.classList.contains("fn__rotate")) { 269 - return; 270 - } 271 - svgElement.classList.add("fn__rotate"); 272 - fetchPost("/api/setting/getCloudUser", { 273 - token: window.siyuan.user.userToken, 274 - }, response => { 275 - window.siyuan.user = response.data; 276 - element.innerHTML = account.genHTML(); 277 - account.bindEvent(element); 278 - showMessage(window.siyuan.languages.refreshUser, 3000); 279 - account.onSetaccount(); 280 - processSync(); 281 - }); 282 - }); 283 - element.querySelector("#logout").addEventListener("click", () => { 284 - fetchPost("/api/setting/logoutCloudUser", {}, () => { 285 - fetchPost("/api/setting/getCloudUser", {}, response => { 286 - window.siyuan.user = response.data; 287 - element.innerHTML = account.genHTML(); 288 - account.bindEvent(element); 289 - account.onSetaccount(); 290 - processSync(); 291 - }); 292 - }); 293 - }); 294 - element.querySelector("#deactivateUser").addEventListener(getEventName(), () => { 295 - confirmDialog("⚠️ " + window.siyuan.languages.deactivateUser, window.siyuan.languages.deactivateUserTip, () => { 296 - fetchPost("/api/account/deactivate", {}, () => { 297 - window.siyuan.user = null; 298 - element.innerHTML = account.genHTML(); 299 - account.bindEvent(element); 300 - account.onSetaccount(); 301 - processSync(); 302 - }); 303 - }); 304 - }); 305 - element.querySelectorAll("input[type='checkbox']").forEach(item => { 306 - item.addEventListener("change", () => { 307 - fetchPost("/api/setting/setAccount", { 308 - displayTitle: (element.querySelector("#displayTitle") as HTMLInputElement).checked, 309 - displayVIP: (element.querySelector("#displayVIP") as HTMLInputElement).checked, 310 - }, (response) => { 311 - window.siyuan.config.account.displayTitle = response.data.displayTitle; 312 - window.siyuan.config.account.displayVIP = response.data.displayVIP; 313 - account.onSetaccount(); 314 - }); 315 - }); 316 - }); 317 - const activationCodeElement = element.querySelector("#activationCode"); 318 - activationCodeElement?.addEventListener("click", () => { 319 - const activationCodeInput = (activationCodeElement.previousElementSibling as HTMLInputElement); 320 - fetchPost("/api/account/checkActivationcode", {data: activationCodeInput.value}, (response) => { 321 - if (0 !== response.code) { 322 - activationCodeInput.value = ""; 323 - } 324 - confirmDialog(window.siyuan.languages.activationCode, response.msg, () => { 325 - if (response.code === 0) { 326 - fetchPost("/api/account/useActivationcode", {data: (activationCodeElement.previousElementSibling as HTMLInputElement).value}, () => { 327 - refreshElement.dispatchEvent(new CustomEvent("click")); 328 - }); 329 - } 330 - }); 331 - }); 332 - }); 333 - return; 334 - } 335 - 336 - const userPasswordElement = element.querySelector("#userPassword") as HTMLInputElement; 337 - const captchaImgElement = element.querySelector("#captchaImg") as HTMLInputElement; 338 - const captchaElement = element.querySelector("#captcha") as HTMLInputElement; 339 - const twofactorAuthCodeElement = element.querySelector("#twofactorAuthCode") as HTMLInputElement; 340 - const loginBtnElement = element.querySelector("#login") as HTMLButtonElement; 341 - const login2BtnElement = element.querySelector("#login2") as HTMLButtonElement; 342 - agreeLoginElement.addEventListener("click", () => { 343 - if (agreeLoginElement.checked) { 344 - loginBtnElement.removeAttribute("disabled"); 345 - } else { 346 - loginBtnElement.setAttribute("disabled", "disabled"); 347 - } 348 - }); 349 - userNameElement.focus(); 350 - userNameElement.addEventListener("keydown", (event) => { 351 - if (event.isComposing) { 352 - event.preventDefault(); 353 - return; 354 - } 355 - if (event.key === "Enter") { 356 - loginBtnElement.click(); 357 - event.preventDefault(); 358 - } 359 - }); 360 - 361 - twofactorAuthCodeElement.addEventListener("keydown", (event) => { 362 - if (event.isComposing) { 363 - event.preventDefault(); 364 - return; 365 - } 366 - if (event.key === "Enter") { 367 - login2BtnElement.click(); 368 - event.preventDefault(); 369 - } 370 - }); 371 - 372 - captchaElement.addEventListener("keydown", (event) => { 373 - if (event.isComposing) { 374 - event.preventDefault(); 375 - return; 376 - } 377 - if (event.key === "Enter") { 378 - loginBtnElement.click(); 379 - event.preventDefault(); 380 - } 381 - }); 382 - userPasswordElement.addEventListener("keydown", (event) => { 383 - if (event.isComposing) { 384 - event.preventDefault(); 385 - return; 386 - } 387 - if (event.key === "Enter") { 388 - loginBtnElement.click(); 389 - event.preventDefault(); 390 - } 391 - }); 392 - let token: string; 393 - let needCaptcha: string; 394 - captchaImgElement.addEventListener("click", () => { 395 - captchaImgElement.setAttribute("src", getCloudURL("captcha") + `/login?needCaptcha=${needCaptcha}&t=${new Date().getTime()}`); 396 - }); 397 - 398 - const cloudRegionElement = element.querySelector("#cloudRegion") as HTMLSelectElement; 399 - cloudRegionElement.addEventListener("change", () => { 400 - window.siyuan.config.cloudRegion = parseInt(cloudRegionElement.value); 401 - element.querySelector(".config-account__center--text").innerHTML = account.genHTML(true); 402 - element.querySelector("#form1").lastElementChild.innerHTML = `<a href="${getCloudURL("forget-pwd")}" class="b3-button b3-button--cancel" target="_blank">${window.siyuan.languages.forgetPassword}</a> 403 - <span class="fn__space${window.siyuan.config.system.container === "ios" ? " fn__none" : ""}"></span> 404 - <a href="${getCloudURL("register")}" class="b3-button b3-button--cancel${window.siyuan.config.system.container === "ios" ? " fn__none" : ""}" target="_blank">${window.siyuan.languages.register}</a>`; 405 - }); 406 - loginBtnElement.addEventListener("click", () => { 407 - fetchPost("/api/account/login", { 408 - userName: userNameElement.value.replace(/(^\s*)|(\s*$)/g, ""), 409 - userPassword: md5(userPasswordElement.value), 410 - captcha: captchaElement.value.replace(/(^\s*)|(\s*$)/g, ""), 411 - cloudRegion: window.siyuan.config.cloudRegion, 412 - }, (data) => { 413 - let messageId; 414 - if (data.code === 1) { 415 - messageId = showMessage(data.msg); 416 - if (data.data.needCaptcha) { 417 - // 验证码 418 - needCaptcha = data.data.needCaptcha; 419 - captchaElement.parentElement.classList.remove("fn__none"); 420 - captchaElement.previousElementSibling.setAttribute("src", 421 - getCloudURL("captcha") + `/login?needCaptcha=${data.data.needCaptcha}`); 422 - captchaElement.value = ""; 423 - return; 424 - } 425 - return; 426 - } 427 - if (data.code === 10) { 428 - // 两步验证 429 - element.querySelector("#form1").classList.add("fn__none"); 430 - element.querySelector("#form2").classList.remove("fn__none"); 431 - twofactorAuthCodeElement.focus(); 432 - token = data.data.token; 433 - return; 434 - } 435 - hideMessage(messageId); 436 - fetchPost("/api/setting/getCloudUser", { 437 - token: data.data.token, 438 - }, response => { 439 - account._afterLogin(response, element); 440 - }); 441 - }); 442 - }); 443 - 444 - login2BtnElement.addEventListener("click", () => { 445 - fetchPost("/api/setting/login2faCloudUser", { 446 - code: twofactorAuthCodeElement.value, 447 - token, 448 - }, response => { 449 - fetchPost("/api/setting/getCloudUser", { 450 - token: response.data.token, 451 - }, userResponse => { 452 - account._afterLogin(userResponse, element); 453 - }); 454 - }); 455 - }); 456 - }, 457 - _afterLogin(userResponse: IWebSocketData, element: Element) { 458 - window.siyuan.user = userResponse.data; 459 - processSync(); 460 - element.innerHTML = account.genHTML(); 461 - account.bindEvent(element); 462 - account.onSetaccount(); 463 - if (element.getAttribute("data-action") === "go-repos") { 464 - if (needSubscribe("") && 0 === window.siyuan.config.sync.provider) { 465 - const dialogElement = hasClosestByClassName(element, "b3-dialog--open"); 466 - if (dialogElement) { 467 - dialogElement.querySelector('.b3-tab-bar [data-name="repos"]').dispatchEvent(new CustomEvent("click")); 468 - element.removeAttribute("data-action"); 469 - } 470 - } else { 471 - hideElements(["dialog"]); 472 - syncGuide(); 473 - } 474 - } 475 - }, 476 - onSetaccount() { 477 - if (repos.element) { 478 - repos.element.innerHTML = ""; 479 - } 480 - if (window.siyuan.config.system.container === "ios") { 481 - return; 482 - } 483 - let html = ""; 484 - if (window.siyuan.config.account.displayVIP) { 485 - if (window.siyuan.user) { 486 - if (window.siyuan.user.userSiYuanProExpireTime === -1) { // 终身会员 487 - html = `<div class="toolbar__item ariaLabel" aria-label="${window.siyuan.languages.account12}">${Constants.SIYUAN_IMAGE_VIP}</div>`; 488 - } else if (window.siyuan.user.userSiYuanProExpireTime > 0) { // 订阅中 489 - if (window.siyuan.user.userSiYuanSubscriptionPlan === 2) { // 试用订阅 490 - html = `<div class="toolbar__item ariaLabel" aria-label="${window.siyuan.languages.account3}"><svg><use xlink:href="#iconVIP"></use></svg></div>`; 491 - } else { // 正常订阅 492 - html = `<div class="toolbar__item ariaLabel" aria-label="${window.siyuan.languages.account10}"><svg class="ft__secondary"><use xlink:href="#iconVIP"></use></svg></div>`; 493 - } 494 - } else if (window.siyuan.user.userSiYuanSubscriptionStatus === -1) { // 未订阅 495 - html = `<div class="toolbar__item ariaLabel" aria-label="${window.siyuan.languages.freeSub}"><svg class="ft__error"><use xlink:href="#iconVIP"></use></svg></div>`; 496 - } 497 - if (window.siyuan.user.userSiYuanOneTimePayStatus === 1) { // 一次性付费功能特性 498 - html += `<div class="toolbar__item ariaLabel" aria-label="${window.siyuan.languages.onepay}"><svg class="ft__success"><use xlink:href="#iconVIP"></use></svg></div>`; 499 - } 500 - } else { // 未登录 501 - html = `<div class="toolbar__item ariaLabel" aria-label="${window.siyuan.languages.freeSub}"><svg class="ft__error"><use xlink:href="#iconVIP"></use></svg></div>`; 502 - } 503 - } 504 - if (window.siyuan.config.account.displayTitle && window.siyuan.user) { 505 - window.siyuan.user.userTitles.forEach(item => { 506 - html += `<div class="toolbar__item ariaLabel" aria-label="${item.name}:${item.desc}">${item.icon}</div>`; 507 - }); 508 - } 509 - document.getElementById("toolbarVIP").innerHTML = html; 510 - } 511 - };
-8
app/src/config/index.ts
··· 8 8 import {initConfigSearch} from "./search"; 9 9 import {fileTree} from "./fileTree"; 10 10 import {exportConfig} from "./exportConfig"; 11 - import {account} from "./account"; 12 11 import {repos} from "./repos"; 13 12 import {keymap} from "./keymap"; 14 13 import {bazaar} from "./bazaar"; ··· 64 63 containerElement.innerHTML = bazaar.genHTML(); 65 64 bazaar.bindEvent(app); 66 65 break; 67 - case "account": 68 - containerElement.innerHTML = account.genHTML(); 69 - account.element = containerElement; 70 - account.bindEvent(account.element); 71 - break; 72 66 case "repos": 73 67 containerElement.innerHTML = repos.genHTML(); 74 68 repos.element = containerElement; ··· 126 120 <li data-name="bazaar" class="b3-list-item${isHuawei() || isInHarmony() ? " fn__none" : ""}"><svg class="b3-list-item__graphic"><use xlink:href="#iconBazaar"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.bazaar}</span></li> 127 121 <li data-name="search" class="b3-list-item"><svg class="b3-list-item__graphic"><use xlink:href="#iconSearch"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.search}</span></li> 128 122 <li data-name="keymap" class="b3-list-item"><svg class="b3-list-item__graphic"><use xlink:href="#iconKeymap"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.keymap}</span></li> 129 - <li data-name="account" class="b3-list-item"><svg class="b3-list-item__graphic"><use xlink:href="#iconAccount"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.account}</span></li> 130 123 <li data-name="repos" class="b3-list-item"><svg class="b3-list-item__graphic"><use xlink:href="#iconCloud"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.cloud}</span></li> 131 124 <li data-name="publish" class="b3-list-item"><svg class="b3-list-item__graphic"><use xlink:href="#iconLanguage"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.publish}</span></li> 132 125 <li data-name="about" class="b3-list-item"><svg class="b3-list-item__graphic"><use xlink:href="#iconInfo"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.about}</span></li> ··· 143 136 <div class="config__tab-container config__tab-container--top fn__none" data-name="bazaar"></div> 144 137 <div class="config__tab-container fn__none" data-name="search"></div> 145 138 <div class="config__tab-container fn__none" style="overflow: scroll" data-name="keymap"></div> 146 - <div class="config__tab-container config__tab-container--full fn__none" data-name="account"></div> 147 139 <div class="config__tab-container fn__none" data-name="repos"></div> 148 140 <div class="config__tab-container fn__none" data-name="publish"></div> 149 141 <div class="config__tab-container fn__none" data-name="about"></div>
-4
app/src/config/search.ts
··· 79 79 .concat(Object.keys(Constants.SIYUAN_KEYMAP.editor.list)) 80 80 .concat(Object.keys(Constants.SIYUAN_KEYMAP.editor.table))), 81 81 82 - // 账号 83 - getLang(["accountTip", "accountName", "password", "captcha", "forgetPassword", "login", "register", 84 - "twoFactorCaptcha", "account1", "account2", "account5"]), 85 - 86 82 // 云端 87 83 getLang(["cloudStorage", "trafficStat", "sync", "backup", "cdn", "total", "sizeLimit", "cloudBackup", 88 84 "cloudBackupTip", "updatePath", "cloudSync", "upload", "download", "syncMode", "syncModeTip",
-2
app/src/index.ts
··· 3 3 import {Model} from "./layout/Model"; 4 4 import {onGetConfig} from "./boot/onGetConfig"; 5 5 import {initBlockPopover} from "./block/popover"; 6 - import {account} from "./config/account"; 7 6 import {addScript, addScriptSync} from "./protyle/util/addScript"; 8 7 import {genUUID} from "./util/genID"; 9 8 import {fetchGet, fetchPost} from "./util/fetch"; ··· 195 194 fetchPost("/api/setting/getCloudUser", {}, userResponse => { 196 195 window.siyuan.user = userResponse.data; 197 196 onGetConfig(response.data.start, this); 198 - account.onSetaccount(); 199 197 setTitle(window.siyuan.languages.siyuanNote); 200 198 initMessage(); 201 199 });
+2 -11
app/src/layout/topBar.ts
··· 6 6 import {workspaceMenu} from "../menus/workspace"; 7 7 import {MenuItem} from "../menus/Menu"; 8 8 import {setMode} from "../util/assets"; 9 - import {openSetting} from "../config"; 10 9 import {openSearch} from "../search/spread"; 11 10 import {App} from "../index"; 12 11 /// #if !BROWSER ··· 38 37 <svg><use xlink:href="#iconForward"></use></svg> 39 38 </button> 40 39 <div class="fn__flex-1 fn__ellipsis" id="drag"><span class="fn__none">开发版,使用前请进行备份 Development version, please backup before use</span></div> 41 - <div id="toolbarVIP" class="fn__flex${window.siyuan.config.readonly ? " fn__none" : ""}"></div> 42 40 <div id="barPlugins" class="toolbar__item ariaLabel" aria-label="${window.siyuan.languages.plugin}"> 43 41 <svg><use xlink:href="#iconPlugin"></use></svg> 44 42 </div> ··· 85 83 const hideElement = toolbarElement.querySelector("#" + itemId); 86 84 const useElement = hideElement.querySelector("use"); 87 85 const menuOptions: IMenu = { 88 - label: itemId === "toolbarVIP" ? window.siyuan.languages.account : hideElement.getAttribute("aria-label"), 89 - icon: itemId === "toolbarVIP" ? "iconAccount" : (useElement ? useElement.getAttribute("xlink:href").substring(1) : undefined), 86 + label: hideElement.getAttribute("aria-label"), 87 + icon: useElement ? useElement.getAttribute("xlink:href").substring(1) : undefined, 90 88 click: () => { 91 89 if (itemId.startsWith("plugin")) { 92 90 hideElement.dispatchEvent(new CustomEvent("click")); ··· 162 160 rect = toolbarElement.querySelector("#barMore").getBoundingClientRect(); 163 161 } 164 162 window.siyuan.menus.menu.popup({x: rect.right, y: rect.bottom, isLeft: true}); 165 - event.stopPropagation(); 166 - break; 167 - } else if (targetId === "toolbarVIP") { 168 - if (!window.siyuan.config.readonly) { 169 - const dialogSetting = openSetting(app); 170 - dialogSetting.element.querySelector('.b3-tab-bar [data-name="account"]').dispatchEvent(new CustomEvent("click")); 171 - } 172 163 event.stopPropagation(); 173 164 break; 174 165 } else if (targetId === "barSearch") {
-22
app/src/mobile/menu/index.ts
··· 11 11 import {activeBlur} from "../util/keyboardToolbar"; 12 12 import {initAI} from "../settings/ai"; 13 13 import {initRiffCard} from "../settings/riffCard"; 14 - import {login, showAccountInfo} from "../settings/account"; 15 14 import {openModel} from "./model"; 16 15 import {initAbout} from "../settings/about"; 17 16 import {getRecentDocs} from "./getRecentDocs"; ··· 38 37 39 38 export const initRightMenu = (app: App) => { 40 39 const menuElement = document.getElementById("menu"); 41 - let accountHTML = ""; 42 - if (window.siyuan.user && !window.siyuan.config.readonly) { 43 - accountHTML = `<div class="b3-menu__item" id="menuAccount"> 44 - <img class="b3-menu__icon" src="${window.siyuan.user.userAvatarURL}"/> 45 - <span class="b3-menu__label">${window.siyuan.user.userName}</span> 46 - </div>`; 47 - } else if (!window.siyuan.config.readonly) { 48 - accountHTML = `<div class="b3-menu__item" id="menuAccount"> 49 - <svg class="b3-menu__icon"><use xlink:href="#iconAccount"></use></svg><span class="b3-menu__label">${window.siyuan.languages.login}</span> 50 - </div>`; 51 - } 52 40 53 41 let aiHTML = `<div class="b3-menu__item${window.siyuan.config.readonly ? " fn__none" : ""}" id="menuAI"> 54 42 <svg class="b3-menu__icon"><use xlink:href="#iconSparkles"></use></svg><span class="b3-menu__label">AI</span> ··· 64 52 <span class="b3-menu__label">${window.siyuan.languages.back}</span> 65 53 </div> 66 54 <div class="b3-menu__items"> 67 - ${accountHTML} 68 55 <div id="menuRecent" class="b3-menu__item"> 69 56 <svg class="b3-menu__icon"><use xlink:href="#iconList"></use></svg><span class="b3-menu__label">${window.siyuan.languages.recentDocs}</span> 70 57 </div> ··· 268 255 openHistory(app); 269 256 event.preventDefault(); 270 257 event.stopPropagation(); 271 - break; 272 - } else if (target.id === "menuAccount") { 273 - event.preventDefault(); 274 - event.stopPropagation(); 275 - if (document.querySelector("#menuAccount img")) { 276 - showAccountInfo(); 277 - return; 278 - } 279 - login(); 280 258 break; 281 259 } 282 260 target = target.parentElement;
-376
app/src/mobile/settings/account.ts
··· 1 - import {openModel} from "../menu/model"; 2 - import {isInIOS} from "../../protyle/util/compatibility"; 3 - import {fetchPost} from "../../util/fetch"; 4 - import {closePanel} from "../util/closePanel"; 5 - import {processSync} from "../../dialog/processSystem"; 6 - import {confirmDialog} from "../../dialog/confirmDialog"; 7 - import {showMessage} from "../../dialog/message"; 8 - import md5 from "blueimp-md5"; 9 - import {getCloudURL, getIndexURL} from "../../config/util/about"; 10 - import {Dialog} from "../../dialog"; 11 - import {hideElements} from "../../protyle/ui/hideElements"; 12 - import {Constants} from "../../constants"; 13 - import {iOSPurchase} from "../../util/iOSPurchase"; 14 - 15 - export const showAccountInfo = () => { 16 - const isIOS = isInIOS(); 17 - let payHTML; 18 - if (isIOS) { 19 - // 已付费 20 - if (window.siyuan.user?.userSiYuanOneTimePayStatus === 1) { 21 - payHTML = `<button class="b3-button b3-button--big" data-action="iOSPay" data-type="subscribe"> 22 - <svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.account4} 23 - </button>`; 24 - } else { 25 - payHTML = `<button class="b3-button b3-button--big" data-action="iOSPay" data-type="subscribe"> 26 - <svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.account10} 27 - </button> 28 - <div class="fn__hr--b"></div> 29 - <button class="b3-button b3-button--success" data-action="iOSPay" data-type="function"> 30 - <svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.onepay} 31 - </button>`; 32 - } 33 - } else { 34 - payHTML = `<a class="b3-button b3-button--big" href="${getIndexURL("pricing.html")}" target="_blank"> 35 - <svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages[window.siyuan.user?.userSiYuanOneTimePayStatus === 1 ? "account4" : "account1"]} 36 - </a>`; 37 - } 38 - payHTML += `<div class="fn__hr--b"></div> 39 - <span class="b3-chip b3-chip--primary b3-chip--hover${(window.siyuan.user && window.siyuan.user.userSiYuanSubscriptionStatus === 2) ? " fn__none" : ""}" id="trialSub"> 40 - <svg class="ft__secondary"><use xlink:href="#iconVIP"></use></svg> 41 - ${window.siyuan.languages.freeSub} 42 - </span> 43 - <div class="fn__hr${(window.siyuan.user && window.siyuan.user.userSiYuanSubscriptionStatus === 2) ? " fn__none" : ""}"></div> 44 - <a href="${getCloudURL("sponsor")}" target="_blank" class="${isIOS ? "fn__none " : ""}b3-chip b3-chip--pink b3-chip--hover"> 45 - <svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'><path fill='#ffe43c' d='M6.4 0h19.2c4.268 0 6.4 2.132 6.4 6.4v19.2c0 4.268-2.132 6.4-6.4 6.4h-19.2c-4.268 0-6.4-2.132-6.4-6.4v-19.2c0-4.268 2.135-6.4 6.4-6.4z'></path> <path fill='#00f5d4' d='M25.6 0h-8.903c-7.762 1.894-14.043 7.579-16.697 15.113v10.487c0 3.533 2.867 6.4 6.4 6.4h19.2c3.533 0 6.4-2.867 6.4-6.4v-19.2c0-3.537-2.863-6.4-6.4-6.4z'></path> <path fill='#01beff' d='M25.6 0h-0.119c-12.739 2.754-20.833 15.316-18.079 28.054 0.293 1.35 0.702 2.667 1.224 3.946h16.974c3.533 0 6.4-2.867 6.4-6.4v-19.2c0-3.537-2.863-6.4-6.4-6.4z'></path> <path fill='#9a5ce5' d='M31.005 2.966c-0.457-0.722-1.060-1.353-1.784-1.849-8.342 3.865-13.683 12.223-13.679 21.416-0.003 3.256 0.67 6.481 1.978 9.463h8.081c0.602 0 1.185-0.084 1.736-0.238-2.1-3.189-3.401-7.624-3.401-12.526 0-7.337 2.921-13.628 7.070-16.266z'></path> <path fill='#f15bb5' d='M32 25.6v-19.2c0-1.234-0.354-2.419-0.998-3.43-4.149 2.638-7.067 8.928-7.067 16.266 0 4.902 1.301 9.334 3.401 12.526 2.693-0.757 4.664-3.231 4.664-6.162z'></path> <path fill='#fff' opacity='0.2' d='M26.972 22.415c-2.889 0.815-4.297 2.21-6.281 3.182 1.552 0.348 3.105 0.461 4.902 0.461 2.644 0 5.363-1.449 6.406-2.519v-1.085c-1.598-0.399-2.664-0.705-5.028-0.039zM4.773 21.612c-0.003 0-0.006-0.003-0.006-0.003-1.726-0.863-3.382-1.205-4.767-1.301v2.487c0.779-0.341 2.396-0.921 4.773-1.182zM17.158 26.599c1.472-0.158 2.57-0.531 3.533-1.002-1.063-0.238-2.126-0.583-3.269-1.079-2.767-1.205-5.63-3.092-10.491-3.034-0.779 0.010-1.495 0.058-2.158 0.132 4.503 2.248 7.882 5.463 12.384 4.983z'></path> <path fill='#fff' opacity='0.2' d='M20.691 25.594c-0.963 0.47-2.061 0.844-3.533 1.002-4.503 0.483-7.882-2.731-12.381-4.983-2.38 0.261-3.994 0.841-4.773 1.179v2.809c0 4.268 2.132 6.4 6.4 6.4h19.197c4.268 0 6.4-2.132 6.4-6.4v-2.065c-1.044 1.069-3.762 2.519-6.406 2.519-1.797 0-3.35-0.113-4.902-0.461z'></path> <path fill='#fff' opacity='0.5' d='M3.479 19.123c0 0.334 0.271 0.606 0.606 0.606s0.606-0.271 0.606-0.606v0c0-0.334-0.271-0.606-0.606-0.606s-0.606 0.271-0.606 0.606v0z'></path> <path fill='#fff' opacity='0.5' d='M29.027 14.266c0 0.334 0.271 0.606 0.606 0.606s0.606-0.271 0.606-0.606v0c0-0.334-0.271-0.606-0.606-0.606s-0.606 0.271-0.606 0.606v0z'></path> <path fill='#fff' d='M9.904 1.688c0 0.167 0.136 0.303 0.303 0.303s0.303-0.136 0.303-0.303v0c0-0.167-0.136-0.303-0.303-0.303s-0.303 0.136-0.303 0.303v0z'></path> <path fill='#fff' d='M2.673 10.468c0 0.167 0.136 0.303 0.303 0.303s0.303-0.136 0.303-0.303v0c0-0.167-0.136-0.303-0.303-0.303s-0.303 0.136-0.303 0.303v0z'></path> <path fill='#fff' opacity='0.6' d='M30.702 9.376c0 0.167 0.136 0.303 0.303 0.303s0.303-0.136 0.303-0.303v0c0-0.167-0.136-0.303-0.303-0.303s-0.303 0.136-0.303 0.303v0z'></path> <path fill='#fff' opacity='0.8' d='M29.236 20.881c0 0.276 0.224 0.499 0.499 0.499s0.499-0.224 0.499-0.499v0c0-0.276-0.224-0.499-0.499-0.499s-0.499 0.224-0.499 0.499v0z'></path> <path fill='#fff' opacity='0.8' d='M15.38 1.591c0.047 0.016 0.101 0.026 0.158 0.026 0.276 0 0.499-0.224 0.499-0.499 0-0.219-0.141-0.406-0.338-0.473l-0.004-0.001c-0.047-0.016-0.101-0.026-0.158-0.026-0.276 0-0.499 0.224-0.499 0.499 0 0.219 0.141 0.406 0.338 0.473l0.004 0.001z'></path> <path fill='#ffdeeb' d='M25.732 8.268c-2.393-2.371-6.249-2.371-8.642 0l-1.089 1.085-1.079-1.089c-2.38-2.39-6.249-2.393-8.639-0.013s-2.393 6.249-0.013 8.639l2.158 2.158 6.474 6.464c0.596 0.593 1.562 0.593 2.158 0l6.474-6.464 2.193-2.158c2.384-2.383 2.384-6.242 0.003-8.622z'></path> <path fill='#fff' d='M17.081 8.268l-1.079 1.085-1.079-1.089c-2.38-2.39-6.249-2.393-8.639-0.013s-2.393 6.249-0.013 8.639l2.158 2.158 2.548 2.487c4.097-1.044 7.627-3.646 9.837-7.254 1.424-2.271 2.284-4.848 2.503-7.518-2.193-0.715-4.606-0.132-6.236 1.504z'></path> </svg> 46 - ${window.siyuan.languages.sponsor} 47 - </a>`; 48 - let userTitlesHTML = ""; 49 - if (window.siyuan.user.userTitles.length > 0) { 50 - userTitlesHTML = '<div class="b3-chips" style="position: absolute">'; 51 - window.siyuan.user.userTitles.forEach((item) => { 52 - userTitlesHTML += `<div class="b3-chip b3-chip--middle b3-chip--primary">${item.icon} ${item.name}</div>`; 53 - }); 54 - userTitlesHTML += "</div>"; 55 - } 56 - let subscriptionHTML = ""; 57 - if (window.siyuan.user.userSiYuanProExpireTime === -1) { 58 - // 终身会员 59 - subscriptionHTML = `<div class="b3-chip b3-chip--secondary">${Constants.SIYUAN_IMAGE_VIP}${window.siyuan.languages.account12}</div>`; 60 - } else if (window.siyuan.user.userSiYuanProExpireTime > 0) { 61 - // 订阅中 62 - const renewHTML = `<div class="fn__hr--b"></div> 63 - <div class="ft__on-surface ft__smaller"> 64 - ${window.siyuan.languages.account6} 65 - ${Math.max(0, Math.floor((window.siyuan.user.userSiYuanProExpireTime - new Date().getTime()) / 1000 / 60 / 60 / 24))} 66 - ${window.siyuan.languages.day} 67 - ${isIOS ? `<a href="javascript:void(0)" data-action="iOSPay" data-type="subscribe">${window.siyuan.languages.clickMeToRenew}</a>` : `<a href="${getCloudURL("subscribe/siyuan")}" target="_blank">${window.siyuan.languages.clickMeToRenew}</a>`} 68 - </div>`; 69 - if (window.siyuan.user.userSiYuanOneTimePayStatus === 1) { 70 - subscriptionHTML = `<div class="b3-chip b3-chip--success"><svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.account7}</div> 71 - <div class="fn__hr--b"></div>`; 72 - } 73 - if (window.siyuan.user.userSiYuanSubscriptionPlan === 2) { 74 - // 订阅试用 75 - subscriptionHTML += `<div class="b3-chip b3-chip--primary"><svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.account3}</div> 76 - ${renewHTML}<div class="fn__hr--b"></div>`; 77 - } else { 78 - subscriptionHTML += `<div class="b3-chip b3-chip--primary"><svg class="ft__secondary"><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.account8}</div> 79 - ${renewHTML}<div class="fn__hr--b"></div>`; 80 - } 81 - if (window.siyuan.user.userSiYuanOneTimePayStatus === 0) { 82 - subscriptionHTML += !isIOS ? `<button class="b3-button b3-button--success" data-action="iOSPay" data-type="function"> 83 - <svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.onepay} 84 - </button>` : `<a class="b3-button b3-button--success" href="${getIndexURL("pricing.html")}" target="_blank"> 85 - <svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.onepay} 86 - </a>`; 87 - } 88 - } else { 89 - if (window.siyuan.user.userSiYuanOneTimePayStatus === 1) { 90 - subscriptionHTML = `<div class="b3-chip b3-chip--success"><svg><use xlink:href="#iconVIP"></use></svg>${window.siyuan.languages.account7}</div> 91 - <div class="fn__hr--b"></div>${payHTML}`; 92 - } else { 93 - subscriptionHTML = payHTML; 94 - } 95 - } 96 - openModel({ 97 - title: window.siyuan.languages.manage, 98 - icon: "iconAccount", 99 - html: `<div class="fn__flex-column"> 100 - <div class="config-account__bg"> 101 - <div class="config-account__cover" style="background-image: url(${window.siyuan.user.userHomeBImgURL})"></div> 102 - <a href="${getCloudURL("settings/avatar")}" class="config-account__avatar" style="background-image: url(${window.siyuan.user.userAvatarURL})" target="_blank"></a> 103 - <div class="config-account__name"> 104 - <div class="fn__hr--b"></div> 105 - <h1> 106 - <a target="_blank" class="fn__a" href="${getCloudURL("member/" + window.siyuan.user.userName)}">${window.siyuan.user.userName}</a> 107 - <span class="ft__on-surface ft__smaller">${0 === window.siyuan.config.cloudRegion ? "ld246.com" : "liuyun.io"}</span> 108 - </h1> 109 - <div class="fn__hr--b"></div> 110 - <div class="fn__hr--b"></div> 111 - <div>${subscriptionHTML}</div> 112 - </div> 113 - ${userTitlesHTML} 114 - </div> 115 - <div class="config-account__info"> 116 - <div class="fn__flex"> 117 - <a class="b3-button b3-button--text${isIOS ? " fn__none" : ""}" href="${getCloudURL("settings")}" target="_blank">${window.siyuan.languages.manage}</a> 118 - <span class="fn__space${isIOS ? " fn__none" : ""}"></span> 119 - <button class="b3-button b3-button--cancel" id="logout"> 120 - ${window.siyuan.languages.logout} 121 - </button> 122 - <span class="fn__space"></span> 123 - <button class="b3-button b3-button--cancel" id="deactivateUser"> 124 - ${window.siyuan.languages.deactivateUser} 125 - </button> 126 - <span class="fn__flex-1"></span> 127 - <button class="b3-button b3-button--cancel" id="refresh"> 128 - <svg><use xlink:href="#iconRefresh"></use></svg> 129 - </button> 130 - </div> 131 - </div></div>`, 132 - bindEvent(modelMainElement: HTMLElement) { 133 - modelMainElement.addEventListener("click", (event) => { 134 - let target = event.target as HTMLElement; 135 - if (typeof event.detail !== "number") { 136 - target = event.detail; 137 - } 138 - while (target && !target.isSameNode(modelMainElement)) { 139 - if (target.getAttribute("data-action") === "iOSPay") { 140 - iOSPurchase(target.getAttribute("data-type")); 141 - event.preventDefault(); 142 - event.stopPropagation(); 143 - break; 144 - } else if (target.id === "logout") { 145 - fetchPost("/api/setting/logoutCloudUser", {}, () => { 146 - window.siyuan.user = null; 147 - closePanel(); 148 - document.getElementById("menuAccount").innerHTML = `<svg class="b3-menu__icon"><use xlink:href="#iconAccount"></use></svg><span class="b3-menu__label">${window.siyuan.languages.login}</span>`; 149 - processSync(); 150 - }); 151 - event.preventDefault(); 152 - event.stopPropagation(); 153 - break; 154 - } else if (target.id === "deactivateUser") { 155 - const dialog = new Dialog({ 156 - title: "⚠️ " + window.siyuan.languages.deactivateUser, 157 - width: "92vw", 158 - content: getLoginHTML(true), 159 - }); 160 - bindLoginEvent(dialog.element.querySelector(".b3-dialog__body"), true); 161 - dialog.element.setAttribute("data-key", Constants.DIALOG_DEACTIVATEUSER); 162 - event.preventDefault(); 163 - event.stopPropagation(); 164 - break; 165 - } else if (target.id === "trialSub") { 166 - fetchPost("/api/account/startFreeTrial", {}, () => { 167 - modelMainElement.dispatchEvent(new CustomEvent("click", { 168 - detail: modelMainElement.querySelector("#refresh") 169 - })); 170 - }); 171 - event.preventDefault(); 172 - event.stopPropagation(); 173 - break; 174 - } else if (target.id === "refresh") { 175 - const svgElement = target.firstElementChild; 176 - if (svgElement.classList.contains("fn__rotate")) { 177 - return; 178 - } 179 - svgElement.classList.add("fn__rotate"); 180 - fetchPost("/api/setting/getCloudUser", { 181 - token: window.siyuan.user.userToken, 182 - }, response => { 183 - window.siyuan.user = response.data; 184 - showMessage(window.siyuan.languages.refreshUser, 3000); 185 - showAccountInfo(); 186 - const menuAccountElement = document.getElementById("menuAccount"); 187 - if (window.siyuan.user) { 188 - menuAccountElement.innerHTML = `<img class="b3-menu__icon" src="${window.siyuan.user.userAvatarURL}"/><span class="b3-menu__label">${window.siyuan.user.userName}</span>`; 189 - } else { 190 - menuAccountElement.innerHTML = `<svg class="b3-menu__icon"><use xlink:href="#iconAccount"></use></svg><span class="b3-menu__label">${window.siyuan.languages.login}</span>`; 191 - } 192 - processSync(); 193 - }); 194 - event.preventDefault(); 195 - event.stopPropagation(); 196 - break; 197 - } 198 - target = target.parentElement; 199 - } 200 - }); 201 - } 202 - }); 203 - }; 204 - 205 - const getLoginHTML = (deactivate = false) => { 206 - let confirmHTML: string; 207 - if (deactivate) { 208 - confirmHTML = `<div class="b3-form__img fn__none"> 209 - <div class="fn__hr--b"></div> 210 - <img id="captchaImg" class="fn__pointer" style="top: 17px;height: 26px;"> 211 - <input id="captcha" class="b3-text-field fn__block" placeholder="${window.siyuan.languages.captcha}"> 212 - </div> 213 - <div class="fn__hr--b"></div> 214 - <button id="login" class="b3-button fn__block">${window.siyuan.languages.deactivateUser}</button>`; 215 - } else { 216 - confirmHTML = `<div class="b3-form__icon"> 217 - <svg class="b3-form__icon-icon"><use xlink:href="#iconFocus"></use></svg> 218 - <select class="b3-select b3-form__icon-input fn__block" id="cloudRegion"> 219 - <option value="0"${window.siyuan.config.cloudRegion === 0 ? " selected" : ""}>${window.siyuan.languages.cloudRegionChina}</option> 220 - <option value="1"${window.siyuan.config.cloudRegion === 1 ? " selected" : ""}>${window.siyuan.languages.cloudRegionNorthAmerica}</option> 221 - </select> 222 - </div> 223 - <div class="b3-form__img fn__none"> 224 - <div class="fn__hr--b"></div> 225 - <img id="captchaImg" class="fn__pointer" style="top: 17px;height: 26px;"> 226 - <input id="captcha" class="b3-text-field fn__block" placeholder="${window.siyuan.languages.captcha}"> 227 - </div> 228 - <div class="fn__hr--b"></div> 229 - <label class="ft__smaller ft__on-surface fn__flex"> 230 - <span class="fn__space"></span> 231 - <input type="checkbox" class="b3-switch fn__flex-center" id="agreeLogin"> 232 - <span class="fn__space"></span> 233 - <span>${window.siyuan.languages.accountTip}</span> 234 - </label> 235 - <div class="fn__hr--b"></div> 236 - <button id="login" disabled class="b3-button fn__block">${window.siyuan.languages.login}</button> 237 - <div class="fn__hr--b"></div> 238 - <div class="ft__center"> 239 - <a href="${getCloudURL("forget-pwd")}" class="b3-button b3-button--cancel" target="_blank">${window.siyuan.languages.forgetPassword}</a> 240 - <span class="fn__space${window.siyuan.config.system.container === "ios" ? " fn__none" : ""}"></span> 241 - <a href="${getCloudURL("register")}" class="b3-button b3-button--cancel${window.siyuan.config.system.container === "ios" ? " fn__none" : ""}" target="_blank">${window.siyuan.languages.register}</a> 242 - </div>`; 243 - } 244 - return `<div class="b3-form__space" id="form1"> 245 - <div class="b3-form__icon"> 246 - <svg class="b3-form__icon-icon"><use xlink:href="#iconAccount"></use></svg> 247 - <input id="userName" class="b3-text-field fn__block b3-form__icon-input" placeholder="${window.siyuan.languages.accountName}"> 248 - </div> 249 - <div class="fn__hr--b"></div> 250 - <div class="b3-form__icon"> 251 - <svg class="b3-form__icon-icon"><use xlink:href="#iconLock"></use></svg> 252 - <input type="password" id="userPassword" class="b3-text-field b3-form__icon-input fn__block" placeholder="${window.siyuan.languages.password}"> 253 - </div> 254 - <div class="fn__hr--b"></div> 255 - ${confirmHTML} 256 - </div> 257 - <div class="b3-form__space fn__none" id="form2"> 258 - <div class="b3-form__icon"> 259 - <svg class="b3-form__icon-icon"><use xlink:href="#iconLock"></use></svg> 260 - <input id="twofactorAuthCode" class="b3-text-field fn__block b3-form__icon-input" placeholder="${window.siyuan.languages.twoFactorCaptcha}"> 261 - </div> 262 - <div class="fn__hr--b"></div> 263 - <button id="login2" class="b3-button fn__block">${deactivate ? window.siyuan.languages.deactivateUser : window.siyuan.languages.login}</button> 264 - </div>`; 265 - }; 266 - 267 - const afterLogin = (response: IWebSocketData, deactive = false) => { 268 - if (deactive) { 269 - hideElements(["dialog"]); 270 - confirmDialog("⚠️ " + window.siyuan.languages.deactivateUser, window.siyuan.languages.deactivateUserTip, () => { 271 - fetchPost("/api/account/deactivate", {}, () => { 272 - window.siyuan.user = null; 273 - closePanel(); 274 - document.getElementById("menuAccount").innerHTML = `<svg class="b3-menu__icon"><use xlink:href="#iconAccount"></use></svg><span class="b3-menu__label">${window.siyuan.languages.login}</span>`; 275 - processSync(); 276 - }); 277 - }); 278 - } else { 279 - fetchPost("/api/setting/getCloudUser", { 280 - token: response.data.token, 281 - }, response => { 282 - window.siyuan.user = response.data; 283 - closePanel(); 284 - document.getElementById("menuAccount").innerHTML = `<img class="b3-menu__icon" src="${window.siyuan.user.userAvatarURL}"/> 285 - <span class="b3-menu__label">${window.siyuan.user.userName}</span>`; 286 - processSync(); 287 - }); 288 - } 289 - }; 290 - 291 - const bindLoginEvent = (modelMainElement: HTMLElement, deactive = false) => { 292 - const agreeLoginElement = modelMainElement.querySelector("#agreeLogin") as HTMLInputElement; 293 - const userNameElement = modelMainElement.querySelector("#userName") as HTMLInputElement; 294 - const userPasswordElement = modelMainElement.querySelector("#userPassword") as HTMLInputElement; 295 - const captchaImgElement = modelMainElement.querySelector("#captchaImg") as HTMLInputElement; 296 - const captchaElement = modelMainElement.querySelector("#captcha") as HTMLInputElement; 297 - const twofactorAuthCodeElement = modelMainElement.querySelector("#twofactorAuthCode") as HTMLInputElement; 298 - const loginBtnElement = modelMainElement.querySelector("#login") as HTMLButtonElement; 299 - const login2BtnElement = modelMainElement.querySelector("#login2") as HTMLButtonElement; 300 - userNameElement.focus(); 301 - let token: string; 302 - let needCaptcha: string; 303 - if (agreeLoginElement) { 304 - agreeLoginElement.addEventListener("click", () => { 305 - if (agreeLoginElement.checked) { 306 - loginBtnElement.removeAttribute("disabled"); 307 - } else { 308 - loginBtnElement.setAttribute("disabled", "disabled"); 309 - } 310 - }); 311 - } 312 - captchaImgElement.addEventListener("click", () => { 313 - captchaImgElement.setAttribute("src", getCloudURL("captcha") + `/login?needCaptcha=${needCaptcha}&t=${new Date().getTime()}`); 314 - }); 315 - 316 - const cloudRegionElement = modelMainElement.querySelector("#cloudRegion") as HTMLSelectElement; 317 - if (cloudRegionElement) { 318 - cloudRegionElement.addEventListener("change", () => { 319 - window.siyuan.config.cloudRegion = parseInt(cloudRegionElement.value); 320 - modelMainElement.querySelector("#form1").lastElementChild.innerHTML = `<a href="${getCloudURL("forget-pwd")}" class="b3-button b3-button--cancel" target="_blank">${window.siyuan.languages.forgetPassword}</a> 321 - <span class="fn__space${window.siyuan.config.system.container === "ios" ? " fn__none" : ""}"></span> 322 - <a href="${getCloudURL("register")}" class="b3-button b3-button--cancel${window.siyuan.config.system.container === "ios" ? " fn__none" : ""}" target="_blank">${window.siyuan.languages.register}</a>`; 323 - }); 324 - } 325 - loginBtnElement.addEventListener("click", () => { 326 - fetchPost("/api/account/login", { 327 - userName: userNameElement.value.replace(/(^\s*)|(\s*$)/g, ""), 328 - userPassword: md5(userPasswordElement.value), 329 - captcha: captchaElement.value.replace(/(^\s*)|(\s*$)/g, ""), 330 - cloudRegion: window.siyuan.config.cloudRegion 331 - }, (data) => { 332 - if (data.code === 1) { 333 - showMessage(data.msg); 334 - if (data.data.needCaptcha) { 335 - // 验证码 336 - needCaptcha = data.data.needCaptcha; 337 - captchaElement.parentElement.classList.remove("fn__none"); 338 - captchaElement.previousElementSibling.setAttribute("src", 339 - getCloudURL("captcha") + `/login?needCaptcha=${data.data.needCaptcha}`); 340 - captchaElement.value = ""; 341 - return; 342 - } 343 - return; 344 - } 345 - if (data.code === 10) { 346 - // 两步验证 347 - modelMainElement.querySelector("#form1").classList.add("fn__none"); 348 - modelMainElement.querySelector("#form2").classList.remove("fn__none"); 349 - twofactorAuthCodeElement.focus(); 350 - token = data.data.token; 351 - return; 352 - } 353 - afterLogin(data, deactive); 354 - }); 355 - }); 356 - 357 - login2BtnElement.addEventListener("click", () => { 358 - fetchPost("/api/setting/login2faCloudUser", { 359 - code: twofactorAuthCodeElement.value, 360 - token, 361 - }, faResponse => { 362 - afterLogin(faResponse, deactive); 363 - }); 364 - }); 365 - }; 366 - 367 - export const login = () => { 368 - openModel({ 369 - title: window.siyuan.languages.login, 370 - icon: "iconAccount", 371 - html: getLoginHTML(), 372 - bindEvent(modelMainElement: HTMLElement) { 373 - bindLoginEvent(modelMainElement); 374 - } 375 - }); 376 - };
-15
app/src/types/config.d.ts
··· 25 25 * Access authorization code 26 26 */ 27 27 accessAuthCode: TAccessAuthCode; 28 - account: IAccount; 29 28 ai: IAI; 30 29 api: IAPI; 31 30 appearance: IAppearance; ··· 95 94 * Access authorization code 96 95 */ 97 96 export type TAccessAuthCode = "" | "*******"; 98 - 99 - /** 100 - * Account configuration 101 - */ 102 - export interface IAccount { 103 - /** 104 - * Display the title icon 105 - */ 106 - displayTitle: boolean; 107 - /** 108 - * Display the VIP icon 109 - */ 110 - displayVIP: boolean; 111 - } 112 97 113 98 /** 114 99 * Artificial Intelligence (AI) related configuration