feat(web): Improve UI styling and add registration prompt
This commit is contained in:
parent
8d4bfe6e3a
commit
e36b701812
@ -1,5 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2024-10-01 - 1.2.0 - feat(web)
|
||||||
|
Improve UI styling and add registration prompt
|
||||||
|
|
||||||
|
- Updated max-width of login container to improve layout consistency
|
||||||
|
- Added new component for user registration
|
||||||
|
- Improved styling for various elements including buttons and text boxes
|
||||||
|
|
||||||
## 2024-10-01 - 1.1.1 - fix(core)
|
## 2024-10-01 - 1.1.1 - fix(core)
|
||||||
Corrected typos and added missing keywords.
|
Corrected typos and added missing keywords.
|
||||||
|
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@idp.global/idp.global',
|
name: '@idp.global/idp.global',
|
||||||
version: '1.1.1',
|
version: '1.2.0',
|
||||||
description: 'An identity provider software managing user authentications, registrations, and sessions.'
|
description: 'An identity provider software managing user authentications, registrations, and sessions.'
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@idp.global/idp.global',
|
name: '@idp.global/idp.global',
|
||||||
version: '1.1.1',
|
version: '1.2.0',
|
||||||
description: 'An identity provider software managing user authentications, registrations, and sessions.'
|
description: 'An identity provider software managing user authentications, registrations, and sessions.'
|
||||||
}
|
}
|
||||||
|
@ -88,31 +88,31 @@ export class IdpLogincontainer extends DeesElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.loginblock {
|
.loginblock {
|
||||||
max-width: 520px;
|
max-width: 500px;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
transform: translate3d(0px, 0px, 0px);
|
transform: translate3d(0px, 0px, 0px);
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
|
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
|
||||||
background: ${cssManager.bdTheme('#ffffff', '#181818')};
|
background: ${cssManager.bdTheme('#ffffff', '#111111')};
|
||||||
border-top: 1px solid ${cssManager.bdTheme('#ffffff', '#333333')};
|
border-top: 1px solid ${cssManager.bdTheme('#ffffff', '#222222')};
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
h1 {
|
||||||
width: 130px;
|
font-size: 24px;
|
||||||
min-height: 34.9px;
|
font-family: 'Cal Sans';
|
||||||
display: block;
|
text-align: center;
|
||||||
margin: auto;
|
letter-spacing:0.0125em;
|
||||||
margin-top: 16px;
|
}
|
||||||
margin-bottom: 25px;
|
|
||||||
filter: ${cssManager.bdTheme('invert(1)', '')};
|
.contentSpacer {
|
||||||
|
padding: 0px 0px 16px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.legalinfo {
|
.legalinfo {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
margin-top: 10px;
|
|
||||||
color: ${cssManager.bdTheme('#666', '#ccc')};
|
color: ${cssManager.bdTheme('#666', '#ccc')};
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 100%;
|
line-height: 100%;
|
||||||
@ -133,10 +133,10 @@ export class IdpLogincontainer extends DeesElement {
|
|||||||
return html`
|
return html`
|
||||||
<div class="mainContainer loginPromptContainer">
|
<div class="mainContainer loginPromptContainer">
|
||||||
<div class="loginblock">
|
<div class="loginblock">
|
||||||
<img
|
<h1>idp.global</h1>
|
||||||
src="https://assetbroker.lossless.one/brandfiles/00general/plain_workspaceglobal.svg"
|
<div class="contentSpacer">
|
||||||
/>
|
|
||||||
<idp-login></idp-login>
|
<idp-login></idp-login>
|
||||||
|
</div>
|
||||||
<div class="legalinfo">
|
<div class="legalinfo">
|
||||||
<a href="https://legal.task.vc/" target="_blank">Legal Info</a>
|
<a href="https://legal.task.vc/" target="_blank">Legal Info</a>
|
||||||
| <a href="https://task.vc/" target="_blank">Company Website</a>
|
| <a href="https://task.vc/" target="_blank">Company Website</a>
|
||||||
|
@ -27,10 +27,6 @@ declare global {
|
|||||||
@customElement('idp-login')
|
@customElement('idp-login')
|
||||||
export class IdpLogin extends DeesElement {
|
export class IdpLogin extends DeesElement {
|
||||||
public static demo = () => html`<idp-login></idp-login>`;
|
public static demo = () => html`<idp-login></idp-login>`;
|
||||||
public static receptionUrl = 'https://reception.lossless.one/typedrequest';
|
|
||||||
|
|
||||||
@property()
|
|
||||||
public activePane: 'login' | 'register' = 'login';
|
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
public productOfInterest: string;
|
public productOfInterest: string;
|
||||||
@ -60,56 +56,18 @@ export class IdpLogin extends DeesElement {
|
|||||||
color: ${cssManager.bdTheme('#333333', '#ffffff')};
|
color: ${cssManager.bdTheme('#333333', '#ffffff')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.box {
|
|
||||||
opacity: 0;
|
|
||||||
cursor: pointer;
|
|
||||||
overflow: hidden;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
height: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.box.active {
|
|
||||||
opacity: 1 !important;
|
|
||||||
height: 360px;
|
|
||||||
cursor: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loginbox {
|
|
||||||
}
|
|
||||||
|
|
||||||
.registerbox {
|
|
||||||
}
|
|
||||||
|
|
||||||
.boxcontent {
|
.boxcontent {
|
||||||
margin: 0px 20px;
|
margin: 0px 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
|
||||||
text-align: center;
|
|
||||||
padding: 32px;
|
|
||||||
line-height: 1.5em;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.registerButton {
|
.registerButton {
|
||||||
display: block;
|
margin-top: 16px;
|
||||||
transition: all 0.2s ease;
|
|
||||||
will-change: transform;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.registerButton:hover {
|
|
||||||
color: #fff;
|
|
||||||
transform: scale(1.02);
|
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
|
||||||
public render(): TemplateResult {
|
public render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="loginbox box ${this.activePane === 'login' ? 'active' : ''}">
|
|
||||||
<div class="boxcontent">
|
<div class="boxcontent">
|
||||||
<dees-form
|
<dees-form
|
||||||
id="loginForm"
|
id="loginForm"
|
||||||
@ -133,36 +91,8 @@ export class IdpLogin extends DeesElement {
|
|||||||
.isPasswordBool=${true}
|
.isPasswordBool=${true}
|
||||||
></dees-input-text>
|
></dees-input-text>
|
||||||
<dees-form-submit id="loginSubmitButton"></dees-form-submit>
|
<dees-form-submit id="loginSubmitButton"></dees-form-submit>
|
||||||
<div class="info">
|
|
||||||
You'll go here: ${this.appData ? html`${this.appData.appUrl}` : html``}
|
|
||||||
<p><span class="registerButton" @click=${() => {this.activePane = 'register'}}>You can also register for a new account.</span></p>
|
|
||||||
</div>
|
|
||||||
</dees-form>
|
</dees-form>
|
||||||
</div>
|
<dees-button type="discreet" class="registerButton">Register instead</dees-button>
|
||||||
</div>
|
|
||||||
<div class="registerbox box ${this.activePane === 'register' ? 'active' : ''}">
|
|
||||||
<div class="boxcontent">
|
|
||||||
<dees-form
|
|
||||||
id="registrationForm"
|
|
||||||
@formData="${(eventArg) => {
|
|
||||||
this.register({
|
|
||||||
emailAddress: eventArg.detail.data.emailAddress,
|
|
||||||
});
|
|
||||||
}}"
|
|
||||||
>
|
|
||||||
<dees-input-text
|
|
||||||
.required=${true}
|
|
||||||
key="emailAddress"
|
|
||||||
label="Email-Address"
|
|
||||||
></dees-input-text>
|
|
||||||
<dees-input-checkbox .label="${'Agree to the Terms and Conditions'}"></dees-input-checkbox>
|
|
||||||
<dees-form-submit>Send Verification Email</dees-form-submit>
|
|
||||||
<div class="info">
|
|
||||||
Already have an account?
|
|
||||||
<p><span class="registerButton" @click=${() => {this.activePane = 'login'}}>Login instead.</span></p>
|
|
||||||
</div>
|
|
||||||
</dees-form>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -174,7 +104,7 @@ export class IdpLogin extends DeesElement {
|
|||||||
const loginSubmitButton: DeesFormSubmit = loginForm.querySelector('#loginSubmitButton');
|
const loginSubmitButton: DeesFormSubmit = loginForm.querySelector('#loginSubmitButton');
|
||||||
const setButtonText = async () => {
|
const setButtonText = async () => {
|
||||||
if (loginPasswordInput.value) {
|
if (loginPasswordInput.value) {
|
||||||
console.log('updating text of loginprompt.')
|
console.log('updating text of loginprompt.');
|
||||||
loginSubmitButton.text = 'Login';
|
loginSubmitButton.text = 'Login';
|
||||||
} else {
|
} else {
|
||||||
loginSubmitButton.text = 'Send magic link (or enter password)';
|
loginSubmitButton.text = 'Send magic link (or enter password)';
|
||||||
|
189
ts_web/elements/idp-registerprompt.ts
Normal file
189
ts_web/elements/idp-registerprompt.ts
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
import * as plugins from '../plugins.js';
|
||||||
|
|
||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
html,
|
||||||
|
type TemplateResult,
|
||||||
|
css,
|
||||||
|
cssManager,
|
||||||
|
state,
|
||||||
|
domtools,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
// third party catalogs
|
||||||
|
import '@uptime.link/webwidget';
|
||||||
|
|
||||||
|
import '@design.estate/dees-catalog';
|
||||||
|
import { DeesForm, DeesFormSubmit, DeesInputText } from '@design.estate/dees-catalog';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'idp-registrationprompt': IdpRegistrationPrompt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('idp-registrationprompt')
|
||||||
|
export class IdpRegistrationPrompt extends DeesElement {
|
||||||
|
public static demo = () => html`<idp-login></idp-login>`;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public productOfInterest: string;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
jwt: string;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
reflect: true,
|
||||||
|
type: Object,
|
||||||
|
})
|
||||||
|
appData: plugins.idpInterfaces.data.IApp;
|
||||||
|
|
||||||
|
public jwtObserable = new domtools.plugins.smartrx.rxjs.Subject<string>();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
domtools.elementBasic.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
font-family: 'Geist Sans';
|
||||||
|
display: block;
|
||||||
|
color: ${cssManager.bdTheme('#333333', '#ffffff')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
opacity: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.boxcontent {
|
||||||
|
margin: 0px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.registerButton {
|
||||||
|
display: block;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
will-change: transform;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.registerButton:hover {
|
||||||
|
color: #fff;
|
||||||
|
transform: scale(1.02);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="boxcontent">
|
||||||
|
<dees-form
|
||||||
|
id="registrationForm"
|
||||||
|
@formData="${(eventArg) => {
|
||||||
|
this.register({
|
||||||
|
emailAddress: eventArg.detail.data.emailAddress,
|
||||||
|
});
|
||||||
|
}}"
|
||||||
|
>
|
||||||
|
<dees-input-text
|
||||||
|
.required=${true}
|
||||||
|
key="emailAddress"
|
||||||
|
label="Email-Address"
|
||||||
|
></dees-input-text>
|
||||||
|
<dees-input-checkbox
|
||||||
|
.label="${'Agree to the Terms and Conditions'}"
|
||||||
|
></dees-input-checkbox>
|
||||||
|
<dees-form-submit>Send Verification Email</dees-form-submit>
|
||||||
|
</dees-form>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async firstUpdated() {
|
||||||
|
const domtoolsInstance = await this.domtoolsPromise;
|
||||||
|
const loginForm: DeesForm = this.shadowRoot.querySelector('#loginForm');
|
||||||
|
const loginPasswordInput: DeesInputText = loginForm.querySelector('#loginPasswordInput');
|
||||||
|
const loginSubmitButton: DeesFormSubmit = loginForm.querySelector('#loginSubmitButton');
|
||||||
|
const setButtonText = async () => {
|
||||||
|
if (loginPasswordInput.value) {
|
||||||
|
console.log('updating text of registrationprompt.');
|
||||||
|
loginSubmitButton.text = 'Login';
|
||||||
|
} else {
|
||||||
|
loginSubmitButton.text = 'Send magic link (or enter password)';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
loginForm.changeSubject.subscribe(() => {
|
||||||
|
console.log(`checking button text ${loginPasswordInput.value}`);
|
||||||
|
setButtonText();
|
||||||
|
});
|
||||||
|
setButtonText();
|
||||||
|
}
|
||||||
|
|
||||||
|
private register = async (valueArg: { emailAddress: string }) => {
|
||||||
|
const registrationForm: DeesForm = this.shadowRoot.querySelector('#registrationForm');
|
||||||
|
registrationForm.setStatus('pending', 'registering...');
|
||||||
|
const firstSignupRequest =
|
||||||
|
new domtools.TypedRequest<plugins.idpInterfaces.request.IReq_FirstRegistration>(
|
||||||
|
'/typedrequest',
|
||||||
|
'firstRegistrationRequest'
|
||||||
|
);
|
||||||
|
const response = await firstSignupRequest
|
||||||
|
.fire({
|
||||||
|
email: valueArg.emailAddress,
|
||||||
|
productSlugOfInterest: this.productOfInterest,
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
registrationForm.setStatus('error', err.message);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
if (response.status === 'ok') {
|
||||||
|
registrationForm.setStatus('success', 'Please check your email!');
|
||||||
|
}
|
||||||
|
console.log(response);
|
||||||
|
};
|
||||||
|
|
||||||
|
public async dispatchJwt(jwtArg?: string) {
|
||||||
|
if (jwtArg !== undefined) {
|
||||||
|
console.log(`dispatching jwt from loginprompt.`);
|
||||||
|
this.jwt = jwtArg;
|
||||||
|
await domtools.plugins.smartdelay.delayFor(200);
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('leleLoginGotJwt', {
|
||||||
|
detail: {
|
||||||
|
jwt: this.jwt,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.jwtObserable.next(this.jwt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleRefreshToken(refreshTokenArg: string, delayDispatchMillisArg = 0) {
|
||||||
|
// a refreshToken binds directly to a session.
|
||||||
|
// the refresh token is used on a continuous basis to get fresh and short-lived jwts
|
||||||
|
const refreshJwt = new domtools.TypedRequest<plugins.idpInterfaces.request.IReq_RefreshJwt>(
|
||||||
|
'/typedrequest',
|
||||||
|
'refreshJwt'
|
||||||
|
);
|
||||||
|
const responseJwt = await refreshJwt.fire({
|
||||||
|
refreshToken: refreshTokenArg,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (responseJwt.jwt) {
|
||||||
|
this.domtools.convenience.smartdelay.delayFor(delayDispatchMillisArg).then(() => {
|
||||||
|
this.dispatchJwt(responseJwt.jwt);
|
||||||
|
});
|
||||||
|
return responseJwt.jwt;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,10 @@ export class IdpWelcome extends DeesElement {
|
|||||||
h1 {
|
h1 {
|
||||||
font-family: 'Cal Sans';
|
font-family: 'Cal Sans';
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
font-size: 24px;
|
||||||
|
margin: 24px auto;
|
||||||
|
padding: 0px 24px;
|
||||||
|
width: 500px;
|
||||||
letter-spacing:0.0125em;
|
letter-spacing:0.0125em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +47,8 @@ export class IdpWelcome extends DeesElement {
|
|||||||
margin: 24px auto;
|
margin: 24px auto;
|
||||||
width: 500px;
|
width: 500px;
|
||||||
background: #111111;
|
background: #111111;
|
||||||
border-radius: 8px;
|
border-radius: 16px;
|
||||||
|
border-top: 1px solid ${cssManager.bdTheme('#ffffff', '#222222')};
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user