Skip to content

Commit 7b8d606

Browse files
committed
Add QR code functionality for crypto wallet addresses in donations panel
1 parent b626ac1 commit 7b8d606

14 files changed

Lines changed: 204 additions & 53 deletions

File tree

packages/ui/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"react": "^18.2.0",
2929
"react-dom": "^18.2.0",
3030
"react-markdown": "^10.1.0",
31+
"react-qr-code": "^2.0.18",
3132
"react-sortablejs": "^6.1.4",
3233
"react-textarea-autosize": "^8.5.9",
3334
"simplebar-react": "^3.3.1",

packages/ui/src/components/editor/common/Button/Button.module.scss

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
cursor: pointer;
1414
background-color: var(--vscode-button-background);
1515
color: var(--vscode-button-foreground);
16+
white-space: nowrap;
1617

1718
&:hover {
1819
background-color: var(--vscode-button-hoverBackground);
@@ -49,8 +50,8 @@
4950
}
5051

5152
&--small {
52-
min-height: 24px;
53-
font-size: 12px;
54-
padding: 2px 8px;
53+
min-height: unset;
54+
font-size: 11px;
55+
padding: 2px 5px;
5556
}
5657
}

packages/ui/src/components/editor/panel/Donations/Donations.module.scss

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,36 @@
22
display: flex;
33
flex-direction: column;
44
padding-top: 4px;
5+
gap: 8px;
56
}
67

78
.wallets {
89
display: flex;
910
flex-direction: column;
10-
gap: 6px;
11-
12-
padding: 4px 12px 4px 12px;
11+
margin: 0 12px;
1312

1413
&__wallet {
1514
display: flex;
16-
flex-direction: column;
17-
gap: 2px;
15+
justify-content: space-between;
16+
align-items: center;
17+
gap: 24px;
18+
19+
&__right {
20+
display: flex;
21+
align-items: center;
22+
gap: 2px;
23+
min-width: 0;
24+
flex: 1;
25+
justify-content: flex-end;
26+
}
1827

19-
span {
20-
word-break: break-all;
21-
opacity: var(--dimmed-opacity);
22-
user-select: text;
28+
&__hash {
29+
font-size: 11px;
30+
color: var(--cwc-text-color-dimmed);
31+
text-align: right;
32+
overflow: hidden;
33+
text-overflow: ellipsis;
34+
white-space: nowrap;
2335
}
2436
}
2537
}

packages/ui/src/components/editor/panel/Donations/Donations.tsx

Lines changed: 59 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import styles from './Donations.module.scss'
22
import { useEffect, useRef, useState } from 'react'
33
import cn from 'classnames'
44
import { Scrollable } from '../Scrollable'
5-
import { ListHeader } from '../ListHeader/ListHeader'
5+
import { Button } from '../../common/Button/Button'
6+
import { Fieldset } from '../Fieldset'
67

78
const get_href_from_url_like_string = (text: string): string | null => {
89
if (/\s/.test(text)) {
@@ -62,7 +63,6 @@ const parse_support_message = (
6263
return { username, href, after_text }
6364
}
6465

65-
// Fallback for when no tags are found
6666
const username = message.trim()
6767
const href = get_href_from_url_like_string(username)
6868
return { username: href ? username : message, href, after_text: '' }
@@ -79,12 +79,12 @@ export type DonationsProps = {
7979
is_revalidating?: boolean
8080
on_fetch_next_page: () => void
8181
has_more?: boolean
82+
on_show_qr_code: (wallet: { name: string; address: string }) => void
8283
}
8384

8485
export const Donations: React.FC<DonationsProps> = (props) => {
8586
const observer_target = useRef<HTMLDivElement>(null)
86-
const [is_wallets_collapsed, set_is_wallets_collapsed] = useState(true)
87-
const [is_donations_collapsed, set_is_donations_collapsed] = useState(false)
87+
const [is_wallets_collapsed, set_wallets_collapsed] = useState(true)
8888

8989
useEffect(() => {
9090
if (!observer_target.current) return
@@ -104,38 +104,53 @@ export const Donations: React.FC<DonationsProps> = (props) => {
104104
return () => observer.unobserve(target)
105105
}, [props.on_fetch_next_page])
106106

107+
const wallets = [
108+
{
109+
name: 'Bitcoin',
110+
address: 'bc1qfzajl0fc4347knr6n5hhuk52ufr4sau04su5te'
111+
},
112+
{
113+
name: 'Ethereum',
114+
address: '0x532eA8CA70aBfbA6bfE35e6B3b7b301b175Cf86D'
115+
},
116+
{
117+
name: 'Monero',
118+
address:
119+
'84whVjApZJtSeRb2eEbZ1pJ7yuBoGoWHGA4JuiFvdXVBXnaRYyQ3S4kTEuzgKjpxyr3nxn1XHt9yWTRqZ3XGfY35L4yDm6R'
120+
}
121+
]
122+
107123
return (
108-
<Scrollable>
109-
<div className={styles.container}>
110-
<ListHeader
111-
title="Crypto wallets"
112-
is_collapsed={is_wallets_collapsed}
113-
on_toggle_collapsed={() => set_is_wallets_collapsed((v) => !v)}
114-
/>
115-
{!is_wallets_collapsed && (
124+
<>
125+
<Scrollable>
126+
<div className={styles.container}>
116127
<div className={styles.wallets}>
117-
<div className={styles.wallets__wallet}>
118-
<strong>Bitcoin</strong>
119-
<span>bc1qfzajl0fc4347knr6n5hhuk52ufr4sau04su5te</span>
120-
</div>
121-
<div className={styles.wallets__wallet}>
122-
<strong>Ethereum</strong>
123-
<span>0x532eA8CA70aBfbA6bfE35e6B3b7b301b175Cf86D</span>
124-
</div>
125-
<div className={styles.wallets__wallet}>
126-
<strong>Monero</strong>
127-
<span>
128-
84whVjApZJtSeRb2eEbZ1pJ7yuBoGoWHGA4JuiFvdXVBXnaRYyQ3S4kTEuzgKjpxyr3nxn1XHt9yWTRqZ3XGfY35L4yDm6R
129-
</span>
130-
</div>
128+
<Fieldset
129+
is_collapsed={is_wallets_collapsed}
130+
label="Crypto wallets"
131+
on_toggle_collapsed={() =>
132+
set_wallets_collapsed(!is_wallets_collapsed)
133+
}
134+
>
135+
{wallets.map((wallet) => (
136+
<div className={styles.wallets__wallet} key={wallet.name}>
137+
<strong>{wallet.name}</strong>
138+
<div className={styles.wallets__wallet__right}>
139+
<span className={styles.wallets__wallet__hash}>
140+
{wallet.address}
141+
</span>
142+
<Button
143+
is_small
144+
on_click={() => props.on_show_qr_code(wallet)}
145+
>
146+
Show QR
147+
</Button>
148+
</div>
149+
</div>
150+
))}
151+
</Fieldset>
131152
</div>
132-
)}
133-
<ListHeader
134-
title="Recent coffees"
135-
is_collapsed={is_donations_collapsed}
136-
on_toggle_collapsed={() => set_is_donations_collapsed((v) => !v)}
137-
/>
138-
{!is_donations_collapsed && (
153+
139154
<div className={styles.donations}>
140155
{props.is_fetching ? (
141156
<>
@@ -202,7 +217,14 @@ export const Donations: React.FC<DonationsProps> = (props) => {
202217
<div
203218
className={styles.donations__inner__donation__note}
204219
>
205-
{donation.support_note}
220+
{donation.support_note
221+
.split(/<br\s*\/?>/i)
222+
.map((line, i, arr) => (
223+
<span key={i}>
224+
{line}
225+
{i < arr.length - 1 && <br />}
226+
</span>
227+
))}
206228
</div>
207229
)}
208230
</div>
@@ -212,8 +234,8 @@ export const Donations: React.FC<DonationsProps> = (props) => {
212234
</>
213235
)}
214236
</div>
215-
)}
216-
</div>
217-
</Scrollable>
237+
</div>
238+
</Scrollable>
239+
</>
218240
)
219241
}

packages/ui/src/components/editor/panel/Page/Page.module.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
display: flex;
1111
align-items: center;
1212
justify-content: space-between;
13-
margin: 5px 12px 6px 10px;
13+
margin: 5px 12px 6px 12px;
1414
position: relative;
1515
height: 20px;
1616

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.container {
2+
display: flex;
3+
flex-direction: column;
4+
align-items: center;
5+
gap: 12px;
6+
}
7+
8+
.qr {
9+
background-color: white;
10+
padding: 16px;
11+
border-radius: 8px;
12+
width: 120px;
13+
height: 120px;
14+
display: flex;
15+
align-items: center;
16+
justify-content: center;
17+
}
18+
19+
.value {
20+
font-family: var(--vscode-editor-font-family);
21+
font-size: 11px;
22+
color: var(--vscode-descriptionForeground);
23+
text-align: center;
24+
word-break: break-all;
25+
user-select: text;
26+
max-width: 100%;
27+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { useState } from 'react'
2+
import { QRCodeModal } from './QRCodeModal'
3+
4+
export default {
5+
component: QRCodeModal
6+
}
7+
8+
export const Default = () => {
9+
const [visible, set_visible] = useState(true)
10+
11+
return visible ? (
12+
<QRCodeModal
13+
title="Bitcoin"
14+
value="bc1qfzajl0fc4347knr6n5hhuk52ufr4sau04su5te"
15+
on_close={() => set_visible(false)}
16+
/>
17+
) : (
18+
<button onClick={() => set_visible(true)}>Show Modal</button>
19+
)
20+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import QRCode from 'react-qr-code'
2+
import styles from './QRCodeModal.module.scss'
3+
import { Modal } from '../Modal'
4+
import { Button } from '../../../common/Button'
5+
6+
type Props = {
7+
title: string
8+
value: string
9+
on_close: () => void
10+
}
11+
12+
export const QRCodeModal: React.FC<Props> = (props) => {
13+
return (
14+
<Modal
15+
title={props.title}
16+
on_background_click={props.on_close}
17+
content_max_height="calc(100vh - 150px)"
18+
content_slot={
19+
<div className={styles.container}>
20+
<div className={styles.qr}>
21+
<QRCode value={props.value} size={100} />
22+
</div>
23+
<div className={styles.value}>{props.value}</div>
24+
</div>
25+
}
26+
footer_slot={
27+
<Button on_click={props.on_close} is_focused={true}>
28+
Close
29+
</Button>
30+
}
31+
/>
32+
)
33+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './QRCodeModal'

packages/ui/src/components/editor/panel/modals/StageFilesModal/StageFilesModal.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ type Props = {
1919
}
2020

2121
export const StageFilesModal: React.FC<Props> = (props) => {
22-
console.log('xxx', props.files)
2322
const [selected_files, set_selected_files] = useState<string[]>(
2423
props.files.map((f) => f.path)
2524
)

0 commit comments

Comments
 (0)