Skip to content

Commit bab42f7

Browse files
authored
refactor(components/widget): extract home view component (#700)
1 parent d46ac92 commit bab42f7

4 files changed

Lines changed: 362 additions & 295 deletions

File tree

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
:host {
2+
display: flex;
3+
flex-direction: column;
4+
flex: 1;
5+
min-height: 0;
6+
}
7+
8+
.widget-header-container {
9+
display: flex;
10+
width: 100%;
11+
box-sizing: border-box;
12+
height: 64px;
13+
padding: var(--Spacings-md) var(--Spacings-2xl);
14+
background-color: var(--primary-color);
15+
justify-content: space-between;
16+
align-items: center;
17+
}
18+
19+
.widget-header {
20+
display: flex;
21+
align-items: center;
22+
gap: var(--Spacings-sm);
23+
}
24+
25+
.widget-header p {
26+
font-family: var(--Font-Family-Inter);
27+
font-size: var(--Font-Size-text-lg);
28+
font-style: normal;
29+
font-weight: var(--Font-Weight-Bold);
30+
line-height: var(--Font-Line-Height-lg);
31+
margin: 0;
32+
}
33+
34+
.widget-body p {
35+
align-self: stretch;
36+
color: var(--Text-paragraph-standard);
37+
font-family: var(--Font-Family-Inter);
38+
font-size: var(--Font-Size-text-base);
39+
font-style: normal;
40+
font-weight: var(--Font-Weight-Regular);
41+
line-height: var(--Font-Line-Height-sm);
42+
}
43+
44+
.white-text {
45+
color: var(--Colors-white);
46+
}
47+
48+
.payment-form {
49+
display: flex;
50+
flex-direction: column;
51+
flex: 1;
52+
gap: var(--Spacings-lg);
53+
}
54+
55+
.payment-form.widget-body {
56+
display: flex;
57+
flex-direction: column;
58+
width: 100%;
59+
box-sizing: border-box;
60+
padding: 0px var(--Spacings-2xl);
61+
flex: 1 1 auto;
62+
gap: var(--Spacings-lg);
63+
}
64+
65+
.primary-button {
66+
width: 100%;
67+
height: 44px;
68+
padding: var(--Spacings-sm) var(--Spacings-md);
69+
color: var(--wm-button-text-color);
70+
border: none;
71+
border-radius: var(--widget-border-radius);
72+
font-family: var(--Font-Family-Inter);
73+
font-weight: var(--Font-Weight-Regular);
74+
font-size: var(--Font-Size-text-sm);
75+
line-height: var(--Font-Line-Height-sm);
76+
cursor: pointer;
77+
transition: all 0.2s ease;
78+
display: flex;
79+
align-items: center;
80+
justify-content: center;
81+
margin-top: auto;
82+
83+
background: var(--primary-color);
84+
}
85+
86+
.primary-button:hover:not(:disabled) {
87+
background: color-mix(in srgb, var(--primary-color) 85%, black 15%);
88+
89+
filter: brightness(0.85);
90+
}
91+
92+
@supports (background: color-mix(in srgb, red, blue)) {
93+
.primary-button:hover:not(:disabled) {
94+
background: color-mix(in srgb, var(--primary-color) 85%, black 15%);
95+
filter: none;
96+
}
97+
}
98+
99+
.primary-button:disabled {
100+
opacity: 0.7;
101+
cursor: not-allowed;
102+
}
103+
104+
@media (max-width: 480px) {
105+
.widget-header-container {
106+
padding: var(--Spacings-xs) var(--Spacings-md);
107+
}
108+
109+
.payment-form.widget-body {
110+
padding: 0px var(--Spacings-md);
111+
}
112+
}
113+
114+
.form-label {
115+
display: flex;
116+
justify-content: flex-start;
117+
align-items: center;
118+
gap: 2px;
119+
color: var(--Text-paragraph-standard);
120+
font-family: var(--Font-Family-Inter);
121+
font-size: var(--Font-Size-text-xs);
122+
font-style: normal;
123+
font-weight: var(--Font-Weight-Regular);
124+
line-height: var(--Font-Line-Height-xs);
125+
}
126+
127+
.form-input {
128+
width: 100%;
129+
height: 48px;
130+
padding: var(--Spacings-md);
131+
border: 1px solid var(--Colors-silver-300, #c9c9c9);
132+
border-radius: var(--Radius-Moderate-rounding, 8px);
133+
font-family: var(--Font-Family-Inter);
134+
font-size: var(--Font-Size-text-base);
135+
font-style: normal;
136+
font-weight: var(--Font-Weight-Regular);
137+
line-height: var(--Font-Line-Height-md);
138+
box-sizing: border-box;
139+
transition: border-color 0.2s ease;
140+
color: var(--Text-paragraph-standard);
141+
background-color: var(--Colors-white);
142+
}
143+
144+
.form-input::placeholder {
145+
color: var(--Text-fields-placeholder-default);
146+
font-family: var(--Font-Family-Inter);
147+
font-size: var(--Font-Size-text-base);
148+
font-style: normal;
149+
font-weight: var(--Font-Weight-Regular);
150+
line-height: var(--Font-Line-Height-md);
151+
}
152+
153+
.form-input:focus {
154+
outline: none;
155+
border-color: var(--Button-Primary-color-default);
156+
box-shadow: 0 0 0 3px
157+
color-mix(in srgb, var(--Button-Primary-color-default) 10%, transparent 90%);
158+
}
159+
160+
.form-input:read-only {
161+
background-color: #f9fafb;
162+
color: var(--Text-fields-placeholder-default);
163+
}
164+
165+
.form-input[aria-invalid='true'] {
166+
border-color: var(--Colors-red-600);
167+
box-shadow: 0 0 0 3px
168+
color-mix(in srgb, var(--Colors-red-600) 10%, transparent 90%);
169+
}
170+
171+
.form-input[aria-invalid='true']:focus {
172+
border-color: var(--Colors-red-600);
173+
box-shadow: 0 0 0 3px
174+
color-mix(in srgb, var(--Colors-red-600) 10%, transparent 90%);
175+
}
176+
177+
.error-message {
178+
color: var(--Colors-red-600);
179+
font-family: var(--Font-Family-Inter);
180+
font-size: var(--Font-Size-text-sm);
181+
font-style: normal;
182+
font-weight: var(--Font-Weight-Regular);
183+
line-height: var(--Font-Line-Height-sm);
184+
margin-top: 4px;
185+
display: block;
186+
}
187+
188+
.form-wallet-address {
189+
display: flex;
190+
flex-direction: column;
191+
align-items: flex-start;
192+
gap: 4px;
193+
align-self: stretch;
194+
}
195+
196+
.divider {
197+
width: 100%;
198+
height: 1px;
199+
margin: var(--Spacings-lg, 24px) 0;
200+
}
201+
202+
.divider + .form-wallet-address {
203+
margin-top: auto;
204+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import { LitElement, html, unsafeCSS } from 'lit'
2+
import { property, state } from 'lit/decorators.js'
3+
import walletTotemIcon from '@c/assets/wm_wallet_totem.svg'
4+
import { CloseBtn } from '@c/shared/components/close-btn'
5+
import { DotsLoader } from '@c/shared/components/dots-loader'
6+
import styles from './home.css?raw'
7+
8+
const DEFAULT_TITLE = 'Future of support'
9+
const DEFAULT_DESCRIPTION =
10+
'Experience the new way to support our content. Activate Web Monetization in your browser. Every visit helps us keep creating the content you love! You can also support us by a one time donation below!'
11+
const DEFAULT_CTA_TEXT = 'Support me'
12+
13+
const COMPONENTS = {
14+
'wm-dots-loader': DotsLoader,
15+
'wm-close-btn': CloseBtn,
16+
}
17+
18+
export interface SubmitEventDetail {
19+
walletAddress: string
20+
onComplete: (error?: string) => void
21+
}
22+
23+
export class HomeView extends LitElement {
24+
@property({ type: String }) title = DEFAULT_TITLE
25+
@property({ type: String }) ctaText = ''
26+
@property({ type: String }) description = DEFAULT_DESCRIPTION
27+
@property({ type: Boolean }) showDescription = true
28+
@property({ type: String }) backgroundColor = '#fff'
29+
30+
@state() private _walletAddress = ''
31+
@state() private _error = ''
32+
@state() private _isSubmitting = false
33+
34+
static styles = unsafeCSS(styles)
35+
36+
connectedCallback(): void {
37+
super.connectedCallback()
38+
for (const [name, elConstructor] of Object.entries(COMPONENTS)) {
39+
if (!customElements.get(name)) {
40+
customElements.define(name, elConstructor)
41+
}
42+
}
43+
}
44+
45+
private triggerClose() {
46+
this.dispatchEvent(new CustomEvent('close'))
47+
}
48+
49+
private onSubmit(ev: SubmitEvent) {
50+
ev.preventDefault()
51+
52+
const formData = new FormData(ev.target as HTMLFormElement)
53+
const walletAddress = String(formData.get('walletAddress') ?? '')
54+
55+
this._isSubmitting = true
56+
this.dispatchEvent(
57+
new CustomEvent<SubmitEventDetail>('submit', {
58+
detail: {
59+
walletAddress,
60+
onComplete: (error) => {
61+
this._isSubmitting = false
62+
this._error = error ?? ''
63+
},
64+
},
65+
}),
66+
)
67+
}
68+
69+
private onInput() {
70+
this._error = ''
71+
}
72+
73+
render() {
74+
const hasError = !!this._error
75+
76+
const descriptionElement = this.showDescription
77+
? html`<p>${this.description || DEFAULT_DESCRIPTION}</p>`
78+
: html`<div class="divider" />`
79+
80+
return html`
81+
<div class="widget-header-container">
82+
<div class="widget-header">
83+
<img src=${walletTotemIcon} alt="header wallet totem" />
84+
<p class="white-text">${this.title || DEFAULT_TITLE}</p>
85+
</div>
86+
87+
<wm-close-btn
88+
@click=${this.triggerClose}
89+
.color=${this.backgroundColor}
90+
></wm-close-btn>
91+
</div>
92+
93+
<form class="payment-form widget-body" @submit=${this.onSubmit}>
94+
${descriptionElement}
95+
96+
<div class="form-wallet-address">
97+
<label class="form-label">
98+
Pay from
99+
<span class="red-text"> * </span>
100+
</label>
101+
102+
<input
103+
class="form-input"
104+
type="text"
105+
name="walletAddress"
106+
placeholder="Enter your wallet address"
107+
@input=${this.onInput}
108+
.value=${this._walletAddress}
109+
?disabled=${this._isSubmitting}
110+
aria-invalid=${hasError}
111+
aria-describedby=${hasError ? 'wallet-error' : ''}
112+
/>
113+
114+
<div id="wallet-error" class="error-message" role="alert">
115+
${this._error}
116+
</div>
117+
</div>
118+
119+
<button
120+
class="primary-button"
121+
type="submit"
122+
?disabled=${this._isSubmitting}
123+
>
124+
${this._isSubmitting
125+
? html`<wm-dots-loader></wm-dots-loader>`
126+
: this.ctaText || DEFAULT_CTA_TEXT}
127+
</button>
128+
</form>
129+
`
130+
}
131+
}

0 commit comments

Comments
 (0)