tangled
alpha
login
or
join now
nichoth.com
/
grain-pwa
forked from
grain.social/grain-pwa
0
fork
atom
WIP PWA for Grain
0
fork
atom
overview
issues
pulls
pipelines
feat: add grain-button atom with loading state
chadtmiller.com
2 months ago
46281cdd
a2e7191e
+84
-22
2 changed files
expand all
collapse all
unified
split
src
components
atoms
grain-button.js
pages
grain-create-gallery.js
+79
src/components/atoms/grain-button.js
···
1
1
+
import { LitElement, html, css } from 'lit';
2
2
+
import './grain-spinner.js';
3
3
+
4
4
+
export class GrainButton extends LitElement {
5
5
+
static properties = {
6
6
+
variant: { type: String },
7
7
+
loading: { type: Boolean },
8
8
+
loadingText: { type: String },
9
9
+
disabled: { type: Boolean, reflect: true }
10
10
+
};
11
11
+
12
12
+
static styles = css`
13
13
+
:host {
14
14
+
display: inline-block;
15
15
+
}
16
16
+
button {
17
17
+
display: flex;
18
18
+
align-items: center;
19
19
+
justify-content: center;
20
20
+
gap: 6px;
21
21
+
border: none;
22
22
+
padding: 8px 16px;
23
23
+
border-radius: 6px;
24
24
+
font-size: var(--font-size-sm);
25
25
+
font-weight: var(--font-weight-semibold);
26
26
+
font-family: inherit;
27
27
+
cursor: pointer;
28
28
+
transition: opacity 0.15s;
29
29
+
}
30
30
+
button:disabled {
31
31
+
opacity: 0.5;
32
32
+
cursor: not-allowed;
33
33
+
}
34
34
+
button.primary {
35
35
+
background: var(--color-accent, #0066cc);
36
36
+
color: white;
37
37
+
}
38
38
+
button.secondary {
39
39
+
background: transparent;
40
40
+
color: var(--color-text-primary);
41
41
+
border: 1px solid var(--color-border);
42
42
+
}
43
43
+
button.danger {
44
44
+
background: #ff4444;
45
45
+
color: white;
46
46
+
}
47
47
+
button.ghost {
48
48
+
background: transparent;
49
49
+
color: var(--color-text-secondary);
50
50
+
padding: 8px;
51
51
+
}
52
52
+
`;
53
53
+
54
54
+
constructor() {
55
55
+
super();
56
56
+
this.variant = 'primary';
57
57
+
this.loading = false;
58
58
+
this.loadingText = '';
59
59
+
this.disabled = false;
60
60
+
}
61
61
+
62
62
+
render() {
63
63
+
return html`
64
64
+
<button
65
65
+
class=${this.variant}
66
66
+
?disabled=${this.disabled || this.loading}
67
67
+
>
68
68
+
${this.loading ? html`
69
69
+
<grain-spinner size="16"></grain-spinner>
70
70
+
${this.loadingText || html`<slot></slot>`}
71
71
+
` : html`
72
72
+
<slot></slot>
73
73
+
`}
74
74
+
</button>
75
75
+
`;
76
76
+
}
77
77
+
}
78
78
+
79
79
+
customElements.define('grain-button', GrainButton);
+5
-22
src/components/pages/grain-create-gallery.js
···
3
3
import { auth } from '../../services/auth.js';
4
4
import { draftGallery } from '../../services/draft-gallery.js';
5
5
import '../atoms/grain-icon.js';
6
6
-
import '../atoms/grain-spinner.js';
6
6
+
import '../atoms/grain-button.js';
7
7
8
8
const UPLOAD_BLOB_MUTATION = `
9
9
mutation UploadBlob($data: String!, $mimeType: String!) {
···
68
68
margin-left: -8px;
69
69
cursor: pointer;
70
70
color: var(--color-text-primary);
71
71
-
}
72
72
-
.post-button {
73
73
-
display: flex;
74
74
-
align-items: center;
75
75
-
gap: 6px;
76
76
-
background: var(--color-accent, #0066cc);
77
77
-
color: white;
78
78
-
border: none;
79
79
-
padding: 8px 16px;
80
80
-
border-radius: 6px;
81
81
-
font-weight: var(--font-weight-semibold);
82
82
-
cursor: pointer;
83
83
-
}
84
84
-
.post-button:disabled {
85
85
-
opacity: 0.5;
86
86
-
cursor: not-allowed;
87
71
}
88
72
.photo-strip {
89
73
display: flex;
···
287
271
<button class="back-button" @click=${this.#handleBack}>
288
272
<grain-icon name="back" size="20"></grain-icon>
289
273
</button>
290
290
-
<button
291
291
-
class="post-button"
274
274
+
<grain-button
292
275
?disabled=${!this.#canPost}
276
276
+
?loading=${this._posting}
277
277
+
loadingText="Posting..."
293
278
@click=${this.#handlePost}
294
294
-
>
295
295
-
${this._posting ? html`<grain-spinner size="16"></grain-spinner> Posting...` : 'Post'}
296
296
-
</button>
279
279
+
>Post</grain-button>
297
280
</div>
298
281
299
282
<div class="photo-strip">