From dde7479040a964ff3f0066781122ba3e35a76d97 Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Mon, 5 May 2025 15:43:23 +0200 Subject: [PATCH 1/2] JS-6992: New onboarding flow --- src/img/icon/onboarding/copy.svg | 4 +++ src/json/text.json | 25 +++++++---------- src/scss/form/button.scss | 1 + src/scss/form/phrase.scss | 31 +++++++++++---------- src/scss/page/auth.scss | 37 ++++++++++++++------------ src/ts/component/form/phrase.tsx | 26 +++--------------- src/ts/component/page/auth/onboard.tsx | 5 ++-- src/ts/component/page/auth/select.tsx | 4 +-- src/ts/component/popup/logout.tsx | 2 +- 9 files changed, 59 insertions(+), 76 deletions(-) create mode 100644 src/img/icon/onboarding/copy.svg diff --git a/src/img/icon/onboarding/copy.svg b/src/img/icon/onboarding/copy.svg new file mode 100644 index 0000000000..7789ca655a --- /dev/null +++ b/src/img/icon/onboarding/copy.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/json/text.json b/src/json/text.json index cdb9ee3658..78cde5adc4 100644 --- a/src/json/text.json +++ b/src/json/text.json @@ -202,6 +202,8 @@ "commonApply": "Apply", "commonDescription": "Description", "commonYourName": "Your Name", + "commonShowHide": "Show / Hide", + "commonShowKey": "Reveal and copy Key", "pluralDay": "day|days", "pluralObject": "Object|Objects", @@ -392,8 +394,8 @@ "authInviteLogin": "Enter", "authInviteEmpty": "Invite code is empty", - "authSelectLogin": "Log In", - "authSelectSignup": "Sign Up", + "authSelectLogin": "I already have the key", + "authSelectSignup": "I am new here", "authDisclaimer": "By continuing you agree to our Terms of Use and Privacy Policy", "authLoginSubmit": "Enter my Vault", @@ -422,13 +424,13 @@ "authOnboardVaultLabel": "Everything inside is encrypted.
It's local-first – everything works offline.
Only you have the key.", "authOnboardVaultButton": "Get my Key", - "authOnboardSoulTitle": "Set your name", - "authOnboardSoulLabel": "Only seen by people you share something with.
There is no central registry of these names.", + "authOnboardSoulTitle": "Add your name", + "authOnboardSoulLabel": "Only seen by people you share something with. There is no central registry for these names.", "authOnboardPhraseTitle": "This is your Key", - "authOnboardPhraseLabel": "Your key replaces login and password. Keep it safe — you control your data. Find it later in app settings.Read more<\/span>", + "authOnboardPhraseLabel": "It replaces login and password. Keep it safe — you control your data.
You can find this key later in app settings.
Read more<\/span>", "authOnboardPhraseSubmit": "Reveal my key", - "authOnboardPhraseNotNow": "Not now", + "authOnboardPhraseNotNow": "Skip", "onboardingExperienceSubTitle": "Build your first space", "onboardingExperienceTypeTitle": "Who Will Use This Space?", @@ -808,13 +810,7 @@ "popupSettingsMobileQRText": "Launch Anytype app, tap \u201cLogin\u201d and then \u201cScan QR code\u201d. Reveal and scan the code below to login to your vault.", "popupSettingsPhraseTitle": "Key", - "popupSettingsPhraseStub": "You take the red pill, you stay in Wonderland, and I show you how deep the rabbit hole goes.", - "popupSettingsPhraseShowPhrase": "Show and copy Key", - "popupSettingsPhraseHidePhrase": "Hide Key", - "popupSettingsPhraseShowQR": "Show QR-code", - "popupSettingsPhraseHideQR": "Hide QR-code", "popupSettingsPhraseText": "Your key protects your vault. You'll need it to sign in if you don't have access to your devices. Keep it in a safe place. Click to show:", - "popupSettingsPhraseBackup": "Back up Key", "popupSettingsPinTitle": "Pin Code", "popupSettingsPinText": "Set a 6-digit PIN for your application screen when unattended. PIN adds a quick layer of privacy for your app. It prevents casual viewing but doesn't enhance data encryption. Your primary data remains secure with your account Key. PIN protection is recommended when you step away from your device.", @@ -1029,7 +1025,6 @@ "popupLogoutTitle": "Make sure you saved your login key", "popupLogoutText": "We have no way to recover your login key - it’s yours alone. Please save it before logging out.", - "popupLogoutCopyButton": "Reveal and copy key", "popupLogoutLogoutButton": "Logout", "popupSpaceCreateLabel": "Encrypted & local-first", @@ -1430,8 +1425,8 @@ "popupMigrationImportText2": "One last thing. The updated version of Anytype on iOS and Android is also available for download! If you haven't already, please scan this QR code to update your devices:", "popupMigrationImportText3": "In case of any issues, you can repeat the migration process using the legacy desktop app or visit our community forum.", - "popupPhraseTitle1": "What is a Key?", - "popupPhraseTitle2": "How to save my key?", + "popupPhraseTitle1": "What is the Key?", + "popupPhraseTitle2": "How to save my Key?", "popupPhraseLabel1": "It is represented by a recovery phrase – 12 random words from which your vault is magically generated on this device.", "popupPhraseLabel2": "Whomever knows the combination of these words owns your vault. Right now, you are the only person in the world who knows it.", "popupPhraseLabel3": "All computational resources on Earth are not enough to break in. If you lose it, it cannot be recovered. So, store it somewhere safe!", diff --git a/src/scss/form/button.scss b/src/scss/form/button.scss index 2412dbc974..2e0be854e5 100644 --- a/src/scss/form/button.scss +++ b/src/scss/form/button.scss @@ -45,6 +45,7 @@ &:hover, &.hover, &.active { background: var(--color-shape-highlight-medium); } } +.button.c48 { @include text-paragraph; height: 48px; border-radius: 8px; padding: 0px 16px; } .button.c36 { @include text-common; height: 36px; border-radius: 6px; padding: 0px 12px; } .button.c32 { @include text-small; height: 32px; border-radius: 6px; padding: 0px 10px; } .button.c28 { @include text-common; height: 28px; border-radius: 6px; padding: 0px 10px; } diff --git a/src/scss/form/phrase.scss b/src/scss/form/phrase.scss index ec48e961b0..10163a5853 100644 --- a/src/scss/form/phrase.scss +++ b/src/scss/form/phrase.scss @@ -13,15 +13,6 @@ } .word:empty { margin: 0px; } - .bg { border-radius: 8px; filter: blur(10px); } - .bg-orange { background: var(--color-orange) !important; user-select: none !important; } - .bg-red { background: var(--color-red) !important; } - .bg-pink { background: var(--color-pink) !important; } - .bg-purple { background: var(--color-purple) !important; } - .bg-blue { background: var(--color-blue) !important; } - .bg-ice { background: var(--color-ice) !important; } - .bg-lime { background: var(--color-lime) !important; } - .placeholder { color: var(--color-text-tertiary); top: 0; display: flex; flex-direction: row; align-items: center; justify-content: center; } #entry { display: inline; font-size: var(--font-size-header3); line-height: 18px; height: 18px; -webkit-user-modify: read-write-plaintext-only; user-select: text; @@ -32,13 +23,21 @@ height: 20px; width: 20px; vertical-align: top; transition: $transitionAllCommon; position: absolute; right: -32px; top: 50%; margin: -10px 0px 0px 0px; cursor: default; } - .icon.see { background-image: url('~img/icon/keyphrase/see0.svg'); } - .icon.see:hover { background-image: url('~img/icon/keyphrase/see1.svg'); } - .icon.hide { background-image: url('~img/icon/keyphrase/hide0.svg'); } - .icon.hide:hover { background-image: url('~img/icon/keyphrase/hide1.svg'); } + .icon.show { background-image: url('~img/icon/keyphrase/hide0.svg'); } + .icon.show:hover { background-image: url('~img/icon/keyphrase/hide1.svg'); } .icon.copy { background-image: url('~img/icon/menu/action/copy0.svg'); display: none; } -} -.phraseWrapper.isReadonly { - #entry { display: none; } + + &.isHidden { + .word { border-radius: 8px; filter: blur(10px); background-color: var(--color-text-primary); } + + .icon.show { background-image: url('~img/icon/keyphrase/see0.svg'); } + .icon.show:hover { background-image: url('~img/icon/keyphrase/see1.svg'); } + } + + &.isReadonly { + #entry { display: none; } + } + + &.hasError { background: #240e07; } } .phraseWrapper.hasError { background: #240e07; } \ No newline at end of file diff --git a/src/scss/page/auth.scss b/src/scss/page/auth.scss index a58fbd4854..19163cb8e3 100644 --- a/src/scss/page/auth.scss +++ b/src/scss/page/auth.scss @@ -15,7 +15,7 @@ html.bodyIndex, html.bodyAuth { --color-button-black-hover: rgba(37, 37, 37, 0.8); --color-button-blank-hover: rgba(23, 23, 23, 0.8); - --color-input-opaque: rgba(23, 23, 23, 0.6) !important; + --color-input-opaque: rgba(255, 255, 255, 0.1) !important; --color-popup: #141414 !important; --color-error: #8a351a !important; @@ -76,13 +76,9 @@ html.bodyIndex, html.bodyAuth { } } - .dotIndicator { - .dot { background-color: var(--color-button-stroke); } - .dot.active { background-color: var(--color-text-primary) !important; } - } .tooltip:not(.menuNote) { - width: 410px; padding: 12px 16px; background: var(--color-popup) !important; color: var(--color-text-secondary) !important; box-shadow: var(--shadow) !important; @include text-common; + min-width: 224px; padding: 12px 16px; background: var(--color-popup) !important; color: var(--color-text-secondary) !important; box-shadow: var(--shadow) !important; @include text-common; white-space: normal; } .tooltip:not(.menuNote) { @@ -133,6 +129,11 @@ html.bodyIndex, html.bodyAuth { .button.blank { border-color: var(--color-button-stroke) !important; color: var(--color-text-primary) !important; background: none; } .button.blank:not(.disabled):hover{ background: var(--color-button-blank-hover) !important; } + + .phraseWrapper { background: var(--color-input-opaque) !important; color: #f8f8f8; } + .phraseWrapper.isHidden { + .word { background-color: #f8f8f8; } + } } html.bodyAuthDeleted { @@ -161,7 +162,7 @@ html.bodyAuthDeleted { .iconObject { margin-bottom: 12px; } .buttons { display: flex; flex-direction: column; align-items: center; gap: 12px 0px; } - .button { width: 192px; @include text-common; } + .button { min-width: 224px; @include text-common; } .button.disabled { color: var(--color-text-tertiary) !important; } .small { color: var(--color-text-secondary) !important; } @@ -184,7 +185,7 @@ html.bodyAuthDeleted { a:hover { color: var(--color-text-primary); } } - .buttons { display: flex; flex-direction: row; gap: 0px 12px; justify-content: center; width: 100%; position: absolute; bottom: -58px; } + .buttons { display: flex; flex-direction: row; gap: 0px 12px; justify-content: center; width: 100%; position: absolute; bottom: -68px; } .footer { .label.disclaimer { color: var(--color-text-tertiary) !important; } @@ -201,7 +202,7 @@ html.bodyAuthDeleted { .error { position: absolute; z-index: 1; width: 100%; left: 0px; top: 0px; transform: translateY(calc(-100% - 16px)); } .title { margin: 0px 0px 20px 0px; } - .phraseWrapper { margin: 0px 0px 20px 0px; background: var(--color-button-blank-hover); } + .phraseWrapper { margin: 0px 0px 20px 0px; } } .pageAuthInvite { @@ -231,7 +232,7 @@ html.bodyAuthDeleted { .pageAuthOnboard, .pageAuthInvite, .pageAuthLogin, .pageAuthDeleted, .pageAuthSetup { .frame { display: flex; flex-direction: column; align-items: center; } - .title { @include text-header3; color: var(--color-text-primary) !important; } + .title { @include text-header1; color: var(--color-text-primary) !important; } .label { @include text-paragraph; color: var(--color-text-secondary) !important; } .bottom { position: fixed; bottom: 24px; left: 0; right: 0; display: flex; flex-direction: row; justify-content: center; align-items: center; gap: 0px 6px; opacity: 0.6; } } @@ -245,29 +246,31 @@ html.bodyAuthDeleted { } .pageAuthOnboard { - .title { margin: 0px 0px 10px 0px; } - .label { width: 400px; margin: 0px 0px 20px 0px; } - .dotIndicator { margin: 0px 0px 12px 0px; } - .button { min-width: 192px; width: auto; } + .title { margin: 0px 0px 8px 0px; } + .label { width: 640px; margin: 0px 0px 34px 0px; } + .button { min-width: 224px; width: auto; } .tooltipLink { color: var(--color-text-primary) !important; } .tooltipLink:hover { text-decoration: underline; } - .phraseWrapper { background: var(--color-input-opaque) !important; } .phraseWrapper, .inputWrapper { margin: 0px 0px 20px 0px; } .phraseWrapper { .icon { display: none; } - .icon.copy { display: block; } + .icon.copy { display: block; right: 16px; background-image: url('~img/icon/onboarding/copy.svg'); } } .inputWrapper { .input { border-radius: 26px; border: none !important; background: var(--color-input-opaque) !important; color: var(--color-text-primary) !important; - font-size: var(--font-size-header3); padding: 36px 26px; width: 392px; height: auto; + font-size: var(--font-size-header3); padding: 0px 26px; height: 72px; width: 480px; height: auto; } .input:hover { filter: brightness(1.2); } .input::placeholder { color: var(--color-text-tertiary) !important; } } + + .stageSoul { + .label { margin: 0px 0px 40px 0px; } + } } .pageAuthDeleted { diff --git a/src/ts/component/form/phrase.tsx b/src/ts/component/form/phrase.tsx index 7c87fd4d54..a65a5125a0 100644 --- a/src/ts/component/form/phrase.tsx +++ b/src/ts/component/form/phrase.tsx @@ -2,7 +2,7 @@ import React, { forwardRef, useRef, useState, useEffect, useImperativeHandle } f import $ from 'jquery'; import { getRange, setRange } from 'selection-ranges'; import { Icon } from 'Component'; -import { J, S, keyboard, Storage } from 'Lib'; +import { J, S, keyboard, translate } from 'Lib'; interface Props { value?: string; @@ -25,18 +25,6 @@ interface PhraseRefProps { focus: () => void; }; -const COLORS = [ - 'pink', - /* - 'orange', - 'red', - 'purple', - 'blue', - 'ice', - 'lime', - */ -]; - const Phrase = forwardRef(({ value = '', className = '', @@ -255,15 +243,9 @@ const Phrase = forwardRef(({
{!phrase.current.length ? : ''} {phrase.current.map((item: string, i: number) => { - const color = COLORS[i % COLORS.length]; - const cn = isHidden ? `bg bg-${color}` : `textColor textColor-${color}`; const word = isHidden ? '•'.repeat(item.length) : item; - return ( - - {word} - - ); + return {word}; })} (({
{placeholder ?
{placeholder}
: ''} - - + + ); diff --git a/src/ts/component/page/auth/onboard.tsx b/src/ts/component/page/auth/onboard.tsx index b888eef248..2dad1361d0 100644 --- a/src/ts/component/page/auth/onboard.tsx +++ b/src/ts/component/page/auth/onboard.tsx @@ -1,6 +1,6 @@ import React, { forwardRef, useRef, useState, useEffect } from 'react'; import { observer } from 'mobx-react'; -import { Frame, Title, Label, Button, DotIndicator, Phrase, Icon, Input } from 'Component'; +import { Frame, Title, Label, Button, Phrase, Icon, Input } from 'Component'; import { I, C, S, U, J, translate, Animation, analytics, keyboard, Renderer, Onboarding, Storage } from 'Lib'; enum Stage { @@ -18,7 +18,7 @@ const PageAuthOnboard = observer(forwardRef<{}, I.PageComponent>(() => { const nameRef = useRef(null); const [ stage, setStage ] = useState(Stage.Phrase); const [ phraseVisible, setPhraseVisible ] = useState(false); - const cnb = []; + const cnb = [ 'c48' ]; const unbind = () => { $(window).off('keydown.onboarding'); @@ -246,7 +246,6 @@ const PageAuthOnboard = observer(forwardRef<{}, I.PageComponent>(() => { {canMoveBack() ? : ''} - <Label id="label" className="animation" text={translate(`authOnboard${Stage[stage]}Label`)} /> diff --git a/src/ts/component/page/auth/select.tsx b/src/ts/component/page/auth/select.tsx index a3bcc8df1a..1566757cb1 100644 --- a/src/ts/component/page/auth/select.tsx +++ b/src/ts/component/page/auth/select.tsx @@ -42,10 +42,10 @@ const PageAuthSelect = forwardRef<{}, I.PageComponent>((props, ref) => { <div className="buttons"> <div className="animation"> - <Button text={translate('authSelectLogin')} color="blank" onClick={onLogin} /> + <Button text={translate('authSelectLogin')} color="blank" className="c48" onClick={onLogin} /> </div> <div className="animation"> - <Button ref={registerRef} text={translate('authSelectSignup')} onClick={onRegister} /> + <Button ref={registerRef} text={translate('authSelectSignup')} className="c48" onClick={onRegister} /> </div> </div> diff --git a/src/ts/component/popup/logout.tsx b/src/ts/component/popup/logout.tsx index edf849cfd8..92cc3883bd 100644 --- a/src/ts/component/popup/logout.tsx +++ b/src/ts/component/popup/logout.tsx @@ -123,7 +123,7 @@ const PopupLogout = forwardRef<{}, I.Popup>(({ param, close }, ref) => { </div> <div ref={buttonsRef} className="buttons"> - <Button text={translate('popupLogoutCopyButton')} color="black" className="c36" onClick={onCopy} onMouseEnter={onMouseEnter} /> + <Button text={translate('commonShowKey')} color="black" className="c36" onClick={onCopy} onMouseEnter={onMouseEnter} /> <Button text={translate('popupLogoutLogoutButton')} color="red" className="c36" onClick={onLogout} onMouseEnter={onMouseEnter} /> </div> </div> From 9366890d6a59f0b0dc3dd4f5ac3cbaf1db4d302f Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Mon, 5 May 2025 15:46:31 +0200 Subject: [PATCH 2/2] JS-6992: New onboarding flow --- src/scss/page/auth.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scss/page/auth.scss b/src/scss/page/auth.scss index 19163cb8e3..0418c52cf5 100644 --- a/src/scss/page/auth.scss +++ b/src/scss/page/auth.scss @@ -253,7 +253,7 @@ html.bodyAuthDeleted { .tooltipLink { color: var(--color-text-primary) !important; } .tooltipLink:hover { text-decoration: underline; } - .phraseWrapper, .inputWrapper { margin: 0px 0px 20px 0px; } + .phraseWrapper, .inputWrapper { margin: 0px 0px 40px 0px; } .phraseWrapper { .icon { display: none; } .icon.copy { display: block; right: 16px; background-image: url('~img/icon/onboarding/copy.svg'); } @@ -262,14 +262,14 @@ html.bodyAuthDeleted { .inputWrapper { .input { border-radius: 26px; border: none !important; background: var(--color-input-opaque) !important; color: var(--color-text-primary) !important; - font-size: var(--font-size-header3); padding: 0px 26px; height: 72px; width: 480px; height: auto; + font-size: var(--font-size-header3); padding: 0px 26px; height: 72px; width: 480px; } .input:hover { filter: brightness(1.2); } .input::placeholder { color: var(--color-text-tertiary) !important; } } .stageSoul { - .label { margin: 0px 0px 40px 0px; } + .label { margin-bottom: 40px; } } }