From 79ad917a2a0dc647167022c0564b94426bd24aca Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 2 Oct 2025 17:31:31 +0200 Subject: [PATCH] New loading screen --- customize.dist/loading.js | 50 +++-- customize.dist/messages.js | 2 + customize.dist/pre-loading.js | 25 ++- .../src/less2/include/colortheme-dark.less | 6 +- .../src/less2/include/colortheme.less | 8 +- customize.dist/src/less2/include/loading.less | 172 +++++++++++------- customize.dist/src/pre-loading.css | 100 ++++++---- www/common/common-interface.js | 18 +- www/common/common-ui-elements.js | 4 +- www/common/loading.js | 2 +- www/common/sframe-common.js | 2 +- 11 files changed, 248 insertions(+), 141 deletions(-) diff --git a/customize.dist/loading.js b/customize.dist/loading.js index a62ea71d3..d7e3849f9 100644 --- a/customize.dist/loading.js +++ b/customize.dist/loading.js @@ -7,27 +7,36 @@ // text #3F4141 define([ '/customize/messages.js', + '/customize/lucide.js', 'less!/customize/src/less2/include/loading.less' -], function (Messages) { +], function (Messages, Lucide) { var urlArgs = window.location.href.replace(/^.*\?([^\?]*)$/, function (all, x) { return x; }); var elem = document.createElement('div'); elem.setAttribute('id', 'cp-loading'); - elem.innerHTML = [ - '', - '
', - '
', - '', - '
', - '', - '

', - '
' - ].join(''); + const logoPath = '/customize/CryptPad_logo_grey.svg';// XXX custom + elem.innerHTML = ` +
+
+ +
+
+
+

+
+ +`; var built = false; var types = ['less', 'drive', 'migrate', 'sf', 'team', 'pad', 'end']; // Msg.loading_state_0, loading_state_1, loading_state_2, loading_state_3, loading_state_4, loading_state_5 @@ -35,6 +44,10 @@ define([ var makeList = function (data) { var c = types.indexOf(data.type); current = c; + const msg = Messages['loading_state_'+c]; + return `${msg}`; + + /* var getLi = function (i) { var check = (i < c || (i === c && data.progress >= 100)) ? 'square-check' : 'square'; @@ -52,6 +65,7 @@ define([ }); list += ''; return list; + */ }; var makeBar = function (data) { var c = types.indexOf(data.type); @@ -100,7 +114,10 @@ define([ if (el2) { el2.innerHTML = makeList(data); } var el3 = document.querySelector('.cp-loading-progress-container'); if (el3) { el3.innerHTML = makeBar(data); } + var el4 = document.querySelector('#cp-loading-status'); + if (el4) { el4.setAttribute('style', ''); } } catch (e) { + console.error(e); } }; window.CryptPad_updateLoadingProgress = updateLoadingProgress; @@ -134,6 +151,7 @@ define([ if (!document.body) { return; } clearInterval(intr); document.body.appendChild(elem); + Lucide.createIcons(); }; intr = setInterval(append, 100); append(); diff --git a/customize.dist/messages.js b/customize.dist/messages.js index 3ca597669..223fc29fd 100755 --- a/customize.dist/messages.js +++ b/customize.dist/messages.js @@ -142,6 +142,8 @@ define(req, function(AppConfig, Default, Language) { Messages.import_note = 'To keep the documents you created and/or stored without being logged in, tick "Import documents from your guest session".'; Messages.admin_creation_note = "Create your first administrator account on this page. Administrators manage instance settings including storage quotas, and have access to moderation tools."; + Messages.loading_encrypted = "end-to-end encrypted"; + return Messages; }); diff --git a/customize.dist/pre-loading.js b/customize.dist/pre-loading.js index 5a033aa6a..404d7917c 100644 --- a/customize.dist/pre-loading.js +++ b/customize.dist/pre-loading.js @@ -3,21 +3,28 @@ // SPDX-License-Identifier: AGPL-3.0-or-later (function () { -var logoPath = '/customize/CryptPad_logo.svg'; +var logoPath = '/customize/CryptPad_logo_grey.svg'; if (location.pathname === '/' || location.pathname === '/index.html') { logoPath = '/api/logo'; } var elem = document.createElement('div'); elem.setAttribute('id', 'placeholder'); -elem.innerHTML = [ - '
', - '', - '
', - '
', - '

Loading...

', - '
' -].join(''); +elem.innerHTML = ` +
+
+

Loading...

+
+ +`; var key = 'CRYPTPAD_STORE|colortheme'; // handle outer if (localStorage[key] && localStorage[key] === 'dark') { diff --git a/customize.dist/src/less2/include/colortheme-dark.less b/customize.dist/src/less2/include/colortheme-dark.less index ac04aaa25..04e7975ee 100644 --- a/customize.dist/src/less2/include/colortheme-dark.less +++ b/customize.dist/src/less2/include/colortheme-dark.less @@ -66,6 +66,7 @@ @cryptpad_color_red_fader: fade(@cryptpad_color_red, 15%); @cryptpad_color_warn_red: @cryptpad_color_red_fade; @cryptpad_color_dark_red: #9e0000; +@cryptpad_color_darker_red: darken(@cryptpad_color_dark_red, 15%); @cryptpad_color_mid_red: #FF8880; @cryptpad_color_light_red: #FFD4D4; @cryptpad_color_light_red_fade: fade(@cryptpad_color_light_red, 20%); @@ -119,12 +120,13 @@ // Loading screen @cp_loading-bg: @cryptpad_color_grey_900; @cp_loading-fg: @cryptpad_text_col; +@cp_loading-color: @cryptpad_color_grey_400; @cp_loading-msg-bg: @cryptpad_color_grey_700; @cp_loading-link: @cryptpad_color_brand_300; @cp_loading-error-bg: @cryptpad_color_warn_red; @cp_loading-error-fg: @cryptpad_text_col; @cp_loading-progress-bg: @cryptpad_color_grey_800; -@cp_loading-progress-bar-bg: @cryptpad_color_brand; +@cp_loading-progress-bar-bg: @cryptpad_color_brand_300; @cp_loading-spinner: @cryptpad_color_grey_600; // Chat @@ -157,7 +159,7 @@ @cp_alerts-warning-bg: @cryptpad_color_yellow_fader; @cp_alerts-warning-fg: @cryptpad_color_light_yellow; @cp_alerts-warning-text: @cryptpad_color_light_yellow; -@cp_alerts-danger-bg: @cryptpad_color_red_fader; +@cp_alerts-danger-bg: @cryptpad_color_darker_red; @cp_alerts-danger-fg: @cryptpad_color_light_red; @cp_alerts-danger-text: @cryptpad_color_light_red; @cp_alerts-info-bg: @cryptpad_color_brand_fadest; diff --git a/customize.dist/src/less2/include/colortheme.less b/customize.dist/src/less2/include/colortheme.less index 8c2759445..cc3ddfbcc 100644 --- a/customize.dist/src/less2/include/colortheme.less +++ b/customize.dist/src/less2/include/colortheme.less @@ -66,6 +66,7 @@ @cryptpad_color_red_fader: fade(@cryptpad_color_red, 15%); @cryptpad_color_warn_red: @cryptpad_color_red_fade; @cryptpad_color_dark_red: #9e0000; +@cryptpad_color_darker_red: darken(@cryptpad_color_dark_red, 10%); @cryptpad_color_mid_red: #FF8880; @cryptpad_color_light_red: #FFD4D4; @cryptpad_color_light_red_fade: fade(@cryptpad_color_light_red, 75%); @@ -118,12 +119,13 @@ // Loading screen @cp_loading-bg: @cryptpad_color_grey_200; @cp_loading-fg: @cryptpad_text_col; +@cp_loading-color: @cryptpad_color_grey_700; @cp_loading-msg-bg: @cryptpad_color_white; @cp_loading-link: @cryptpad_color_brand; @cp_loading-error-bg: @cryptpad_color_warn_red; @cp_loading-error-fg: @cryptpad_text_col; @cp_loading-progress-bg: @cryptpad_color_white; -@cp_loading-progress-bar-bg: @cryptpad_color_brand; +@cp_loading-progress-bar-bg: @cryptpad_color_brand_300; @cp_loading-spinner: @cryptpad_color_grey_500; // Chat @@ -156,9 +158,9 @@ @cp_alerts-warning-bg: @cryptpad_color_yellow_fade; @cp_alerts-warning-fg: @cryptpad_color_light_yellow; @cp_alerts-warning-text: darken(@cp_alerts-warning-fg, 55%); -@cp_alerts-danger-bg: @cryptpad_color_light_red_fade; +@cp_alerts-danger-bg: @cryptpad_color_light_red; @cp_alerts-danger-fg: @cryptpad_color_light_red; -@cp_alerts-danger-text: darken(@cp_alerts-danger-fg, 55%); +@cp_alerts-danger-text: @cryptpad_color_darker_red; @cp_alerts-info-bg: fade(@cryptpad_color_brand, 15%); @cp_alerts-info-text: @cryptpad_color_brand; @cp_alerts-info-fg: @cryptpad_color_brand; diff --git a/customize.dist/src/less2/include/loading.less b/customize.dist/src/less2/include/loading.less index 8fa4f428f..5a5bb6ec8 100644 --- a/customize.dist/src/less2/include/loading.less +++ b/customize.dist/src/less2/include/loading.less @@ -37,7 +37,7 @@ opacity: 1; display: flex; flex-flow: column; - justify-content: center; + justify-content: space-between; align-items: center; font: 20px 'Open Sans', 'Helvetica Neue', sans-serif !important; &.cp-loading-transparent { @@ -49,23 +49,27 @@ transition: opacity 0.75s, visibility 0s 0.75s; } .cp-loading-logo { - height: 300px; - width: 300px; - margin-top: 50px; flex: 0 1 auto; min-height: 0; - text-align: center; - } - .cp-loading-logo img { - max-width: 100%; - max-height: 100%; + display: flex; + align-items: center; + gap: 1rem; + color: @cp_loading-spinner; + + img { + margin: 0; + max-height: 60px; + } + span { + font-size: 40px; + font-family: "IBM Plex Mono"; + .tools_unselectable(); + } } .cp-loading-container { width: 700px; max-width: 90vw; - min-height: 236px; max-height: calc(100vh - 20px); - margin: 50px; flex-shrink: 0; display: flex; flex-flow: column; @@ -84,30 +88,45 @@ @media screen and (max-width: 500px) { font-size: 16px !important; - .cp-loading-container { - height: 206px; - } } - @media screen and (max-height: 700px) { - font-size: 16px !important; - .cp-loading-container { - height: 206px; - } - } - @media screen and (max-height: 500px) { + @media screen and (max-width: 300px) { .cp-loading-logo { - display: none; + img { + max-height: 40px; + } + span { + font-size: 20px; + } } } + @media screen and (max-height: 600px) { + font-size: 16px !important; + } #cp-loading-message { background: @cp_loading-msg-bg; - padding: 20px; + padding: 1rem; width: 100%; border-radius: @variables_radius; color: @cp_loading-fg; text-align: left; - display: none; overflow-y: auto; + &.cp-error-message, &.cp-error-message-alt { + margin: 0; + font-size: 16px; + padding: 0.5rem; + width: auto; + } + &.cp-error-message { + background-color: @cp_alerts-danger-bg; + color: @cp_alerts-danger-text; + } + &.cp-error-message-alt { + background-color: @cp_alerts-danger-text; + color: @cp_alerts-danger-bg; + } + &:empty { + display: none; + } a { color: @cp_loading-link; border-radius: @variables_radius; @@ -116,13 +135,34 @@ margin-bottom: 0; } } + #cp-loading-status { + display: flex; + color: @cp_loading-color; + align-items: center; + font-family: "IBM Plex Mono"; + padding-top: 0.5rem; + gap: 0.5rem; + svg { + margin: 0; + } + } + + #cp-loading-footer { + margin-bottom: 2rem; + display: flex; + flex-flow: column; + align-items: center; + } #cp-loading-password-prompt { p.cp-password-error { - color: @cp_loading-error-fg; - background: @cp_loading-error-bg; - padding: 5px; - margin-bottom: 15px; + margin: 0; + margin-bottom: 0.5rem; + font-size: 16px; + padding: 0.5rem; + background-color: @cp_alerts-danger-bg; + color: @cp_alerts-danger-text; + border-radius: @variables_radius; } .cp-password-form { display: flex; @@ -130,7 +170,7 @@ gap:0.5rem; width: 100%; .cp-password-container { - flex-shrink: 1; + flex: 1; min-width: 0; } .cp-password-reveal { @@ -152,14 +192,9 @@ p.cp-password-info { text-align: left; - margin-bottom: 15px; + margin-bottom: 0.5rem; } - .cp-loading-spinner-container { - position: relative; - height: 80px; - margin-bottom: 50px; - } .cp-loading-progress { width: 100%; text-align: center; @@ -170,39 +205,23 @@ text-overflow: ellipsis; } .cp-loading-progress-list { - text-align: left; display: inline-block; - margin-bottom: 50px; max-width: 100%; - ul { - list-style: none; - padding-left: 0; - margin: 0; - } - li { - padding: 0px 5px; - .tools_unselectable(); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - span { - margin-left: 10px; - &.percent { - position: absolute; - } - } - } + color: @cp_loading-color; } .cp-loading-progress-bar { - height: 24px; + margin: 1rem 0; + height: 5px; background: @cp_loading-progress-bg; - border: 1px solid @cp_loading-progress-bar-bg; + border: 0; + //border: 1px solid @cp_loading-progress-bar-bg; border-radius: @variables_radius; } .cp-loading-progress-bar-value { height: 100%; background: @cp_loading-progress-bar-bg; + border-radius: @variables_radius; } } @@ -216,17 +235,36 @@ } } - .cp-spinner-main { - display: inline-block; - box-sizing: border-box; - width: 80px; - height: 80px; - border: 11px solid @cp_loading-spinner; - border-radius: 50%; - border-top-color: transparent; - animation: spin infinite 3s; - animation-timing-function: cubic-bezier(.6,0.15,0.4,0.85); + .cp-loading-spinner-container { + margin: 1rem 0; + height: 5px; + width: 100%; + border: 0; + overflow: hidden; + background: @cp_loading-progress-bg; + border-radius: @variables_radius; } + .cp-spinner-main { + width: 100%; + height: 5px; + background: @cp_loading-progress-bar-bg; + border-radius: @variables_radius; + animation: loading-animation 1s infinite linear; + transform-origin: 0% 50%; + } + +@keyframes loading-animation { + 0% { + transform: translateX(0) scaleX(0); + } + 40% { + transform: translateX(0) scaleX(0.4); + } + 100% { + transform: translateX(100%) scaleX(0.5); + } +} + button { .cp-spinner { diff --git a/customize.dist/src/pre-loading.css b/customize.dist/src/pre-loading.css index c7ea7856b..deeddcea7 100644 --- a/customize.dist/src/pre-loading.css +++ b/customize.dist/src/pre-loading.css @@ -4,6 +4,23 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ +@font-face { + font-family: 'IBM Plex Mono'; + font-style: normal; + font-weight: 500; + src: url("/customize/fonts/IBMPlexMono-Medium.woff2") format("woff2"), url("/customize/fonts/IBMPlexMono-Medium.woff") format("woff"); } + +@font-face { + font-family: 'Open Sans'; + src: url('/components/open-sans-fontface/fonts/Regular/OpenSans-Regular.eot'); + src: url('/components/open-sans-fontface/fonts/Regular/OpenSans-Regular.eot?#iefix') format('embedded-opentype'), + url('/components/open-sans-fontface/fonts/Regular/OpenSans-Regular.woff') format('woff'), + url('/components/open-sans-fontface/fonts/Regular/OpenSans-Regular.ttf') format('truetype'), + url('/components/open-sans-fontface/fonts/Regular/OpenSans-Regular.svg#OpenSansLight') format('svg'); + font-weight: 300; + font-style: normal; +} + .cp-app-noscroll body { background: transparent; } @@ -21,61 +38,75 @@ left: 0px; right: 0px; background-color: #EEEEEE; /* @cp_loading-bg */ - color: #424242; /* @cp_loading-fg */ + color: #757575; /* grey_600 */ font-size: 1.3em; line-height: 120%; opacity: 1; display: flex; flex-flow: column; - justify-content: center; + justify-content: space-between; align-items: center; - font: 20px 'Helvetica Neue', sans-serif !important; + font: 20px 'Open Sans', sans-serif !important; } -html:not(.cp-app-noscroll) #placeholder.dark-theme { +html #placeholder.dark-theme { background-color: #212121; /* @cp_loading-bg (dark) */ } #placeholder.dark-theme { - color: #EEEEEE; /* @cp_loading-fg (dark) */ + color: #BDBDBD; /* grey_400 */ } #placeholder .placeholder-logo-container { - height: 300px; - width: 300px; - margin-top: 50px; - flex: 0 1 auto; - min-height: 0; - text-align: center; - opacity: 0; - animation: fadein 5s ease 2s forwards; + display: flex; + align-items: center; + gap: 1rem; } #placeholder .placeholder-logo-container img { - max-width: 100%; - max-height: 100%; + margin: 0; + max-height: 60px; +} +#placeholder .placeholder-logo-container span { + font-size: 40px; + font-family: "IBM Plex Mono"; + user-select: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + cursor: pointer; } #placeholder .placeholder-message-container { width: 700px; max-width: 90vw; - height: 236px; + height: auto; max-height: calc(100vh - 20px); - margin: 50px; flex-shrink: 0; display: flex; flex-flow: column; align-items: center; + justify-content: center; opacity: 0; animation: fadein 5s ease 2s forwards; } #placeholder .placeholder-message-container p { margin-top: 0; } -#placeholder .placeholder-logo { - margin-left: auto; - margin-right: auto; - max-width: 90vw; - max-height: max(40vh, 250px); - width: auto; - height: auto; - margin-bottom: 2em; + +#placeholder-loading-status { + font-size: 20px; + padding-top: 0.5rem; + font-family: "IBM Plex Mono"; +} +#placeholder-loading-footer { + margin-bottom: 2rem; + display: flex; + flex-flow: column; + align-items: center; + + flex: 0 1 auto; + min-height: 0; + opacity: 0; + animation: fadein 5s ease 2s forwards; } @keyframes fadein { @@ -87,22 +118,19 @@ html:not(.cp-app-noscroll) #placeholder.dark-theme { #placeholder { font-size: 16px !important; } - #placeholder .placeholder-message-container { - height: 206px; +} +@media screen and (max-width: 300px) { + #placeholder .placeholder-logo-container img { + max-height: 40px; + } + #placeholder .placeholder-logo-container span { + font-size: 20px; } } -@media screen and (max-height: 700px) { +@media screen and (max-height: 600px) { #placeholder { font-size: 16px !important; } - #placeholder .placeholder-message-container { - height: 206px; - } -} -@media screen and (max-height: 500px) { - #placeholder .placeholder-logo-container { - display: none; - } } :is(div, noscript) > p.noscript { font-family: sans-serif; diff --git a/www/common/common-interface.js b/www/common/common-interface.js index c5b5b9340..eec050393 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -1082,10 +1082,12 @@ define([ $('.cp-loading-spinner-container').show(); } // Add loading text + const $message = $('#' + LOADING).find('#cp-loading-message'); + $message.removeClass('cp-error-message cp-error-message-alt'); if (loadingText) { - $('#' + LOADING).find('#cp-loading-message').show().text(loadingText); + $message.show().text(loadingText); } else { - $('#' + LOADING).find('#cp-loading-message').hide().text(''); + $message.hide().text(''); } }; if ($('#' + LOADING).length) { @@ -1124,7 +1126,7 @@ define([ $loading.find('.cp-loading-logo').hide(); $loading.append(content); }; - UI.errorLoadingScreen = function (error, transparent, exitable) { + UI.errorLoadingScreen = function (error, transparent, exitable, errorCls) { if (error === 'Error: XDR encoding failure') { console.warn(error); return; @@ -1143,11 +1145,19 @@ define([ // Add the error message var $error = $loading.find('#cp-loading-message').show(); + $error.removeClass('cp-error-message cp-error-message-alt'); if (error instanceof Element) { $error.html('').append(error); } else { + errorCls = true; $error.html(error || Messages.error); } + + if (errorCls) { + const cls = transparent ? 'cp-error-message-alt' + : 'cp-error-message'; + $error.addClass(cls); + } $error.find('a[href]').click(function (e) { e.preventDefault(); var href = $(this).prop('href'); @@ -1689,7 +1699,7 @@ define([ var input = split[1]; // User/admin manual input var text = UI.getDestroyedPlaceholderMessage(code, isAccount); var reasonBlock = input ? h('p', Messages._getKey('dph_reason', [input])) : undefined; - return h('div', [ + return h('div.cp-loading-error', [ h('p', text), reasonBlock ]); diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 2860c9af5..beedec149 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -3209,7 +3209,7 @@ define([ } if (err.message && err.drive) { - let msg = UI.getDestroyedPlaceholder(err.message, true); + let msg = UI.getDestroyedPlaceholder(err.message, true, false, true); return UI.errorLoadingScreen(msg, false, () => { // When closing error screen if (err.message === 'PASSWORD_CHANGE') { @@ -3221,7 +3221,7 @@ define([ if (err.message && (err.message !== "PASSWORD_CHANGE" || viewer)) { // If readonly, tell the viewer that their link won't work with the new password UI.errorLoadingScreen(UI.getDestroyedPlaceholder(err.message, false), - exitable, exitable); + exitable, exitable, true); return; } diff --git a/www/common/loading.js b/www/common/loading.js index 87b961aa6..cc3758212 100644 --- a/www/common/loading.js +++ b/www/common/loading.js @@ -8,7 +8,7 @@ try { var theme = req.theme; var os = req.themeOS; window.CryptPad_theme = theme || os; - if ((theme || os) === 'dark') { + if ((theme || os) === 'dark') { var s = document.createElement('style'); s.innerHTML = 'body { background: black; }'; document.body.appendChild(s); diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 69abc5927..049fd8d20 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -937,7 +937,7 @@ define([ } UI.errorLoadingScreen(msg, false, function () { funcs.gotoURL('/drive/'); - }); + }, true); }); ctx.sframeChan.on('EV_UNIVERSAL_EVENT', function (obj) {