@lukso/transaction-view-core 0.3.1-dev.a8c9315
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +33 -0
- package/CHANGELOG.md +104 -0
- package/LICENSE +201 -0
- package/README.md +264 -0
- package/dist/index.cjs +4573 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +493 -0
- package/dist/index.d.ts +493 -0
- package/dist/index.js +4534 -0
- package/dist/index.js.map +1 -0
- package/dist/shared/index.cjs +2480 -0
- package/dist/shared/index.cjs.map +1 -0
- package/dist/shared/index.d.cts +887 -0
- package/dist/shared/index.d.ts +887 -0
- package/dist/shared/index.js +2437 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/styles/index.cjs +58 -0
- package/dist/styles/index.cjs.map +1 -0
- package/dist/styles/index.d.cts +9 -0
- package/dist/styles/index.d.ts +9 -0
- package/dist/styles/index.js +31 -0
- package/dist/styles/index.js.map +1 -0
- package/package.json +57 -0
- package/publish.log +0 -0
- package/src/components/asset-card.ts +426 -0
- package/src/components/contract-card.ts +238 -0
- package/src/components/description-view.ts +605 -0
- package/src/components/index.ts +20 -0
- package/src/components/info-panel.ts +437 -0
- package/src/components/permissions-block.ts +138 -0
- package/src/components/transaction-playback.ts +429 -0
- package/src/components/universal-token-view.ts +281 -0
- package/src/declaration.d.ts +4 -0
- package/src/examples/INTEGRATION_GUIDE.md +240 -0
- package/src/examples/TransactionContentWithReplacement.vue +269 -0
- package/src/index.ts +38 -0
- package/src/registry/index.ts +31 -0
- package/src/registry/lit-view-loader.ts +191 -0
- package/src/shared/address-display.ts +370 -0
- package/src/shared/address-view.ts +385 -0
- package/src/shared/custom-select.ts +164 -0
- package/src/shared/function-name-view.ts +89 -0
- package/src/shared/gas-provider-view.ts +218 -0
- package/src/shared/icon-view.ts +288 -0
- package/src/shared/image-list.ts +261 -0
- package/src/shared/image-loader-controller.ts +160 -0
- package/src/shared/index.ts +34 -0
- package/src/shared/load-web-components.ts +56 -0
- package/src/shared/notification-view.ts +132 -0
- package/src/shared/progress-view.ts +86 -0
- package/src/shared/safe-custom-element.ts +35 -0
- package/src/shared/scroll-to-bottom-button.ts +55 -0
- package/src/shared/signal-controller.ts +124 -0
- package/src/shared/transaction-view-controller.ts +345 -0
- package/src/shared/url-view.ts +129 -0
- package/src/shared/value-view.ts +510 -0
- package/src/styles/index.ts +28 -0
- package/src/styles/styles.css +1 -0
- package/src/vue-entry.ts +15 -0
- package/tailwind.config.cjs +9 -0
- package/tsconfig.json +22 -0
- package/tsup.config.ts +90 -0
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
import { Task } from '@lit/task'
|
|
2
|
+
import {
|
|
3
|
+
type ResolvedAddress,
|
|
4
|
+
useAddressResolver,
|
|
5
|
+
} from '@lukso/transaction-view-headless'
|
|
6
|
+
import { css, html, LitElement } from 'lit'
|
|
7
|
+
import { property, state } from 'lit/decorators.js'
|
|
8
|
+
import { classMap } from 'lit/directives/class-map.js'
|
|
9
|
+
import { repeat } from 'lit/directives/repeat.js'
|
|
10
|
+
import { when } from 'lit/directives/when.js'
|
|
11
|
+
import { safeCustomElement } from '../shared/safe-custom-element'
|
|
12
|
+
import '../shared/icon-view.js'
|
|
13
|
+
import '../shared/address-view.js'
|
|
14
|
+
import '../shared/image-list.js'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Expandable info panel for displaying detailed asset information
|
|
18
|
+
* Auto-resolves data from address or address-tokenId
|
|
19
|
+
*/
|
|
20
|
+
@safeCustomElement('info-panel')
|
|
21
|
+
export class InfoPanel extends LitElement {
|
|
22
|
+
/**
|
|
23
|
+
* Address or address-tokenId to display info for
|
|
24
|
+
*/
|
|
25
|
+
@property({ type: String })
|
|
26
|
+
address = ''
|
|
27
|
+
|
|
28
|
+
@property({ type: Boolean, attribute: 'open' })
|
|
29
|
+
open = false
|
|
30
|
+
|
|
31
|
+
@property({ type: String })
|
|
32
|
+
standard = ''
|
|
33
|
+
|
|
34
|
+
@property({ type: String })
|
|
35
|
+
type: 'transfer' | 'mint' | 'burn' | 'approve' = 'transfer'
|
|
36
|
+
|
|
37
|
+
@state()
|
|
38
|
+
private _isAnimating = false
|
|
39
|
+
|
|
40
|
+
@state()
|
|
41
|
+
private _resolvedData?: ResolvedAddress
|
|
42
|
+
|
|
43
|
+
private _resolutionTask = new Task(this, {
|
|
44
|
+
task: async ([address]) => {
|
|
45
|
+
if (!address) return null
|
|
46
|
+
|
|
47
|
+
const { resolveAddress } = useAddressResolver()
|
|
48
|
+
// Resolve the full address (including tokenId if present) to get token-specific data
|
|
49
|
+
const data = await resolveAddress(address as string)
|
|
50
|
+
this._resolvedData = data
|
|
51
|
+
return data
|
|
52
|
+
},
|
|
53
|
+
args: () => [this.address] as const,
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
private _extractBaseAddress(addressOrComposite: string): string {
|
|
57
|
+
return addressOrComposite.split('-')[0]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private _extractTokenId(addressOrComposite: string): string | undefined {
|
|
61
|
+
const parts = addressOrComposite.split('-')
|
|
62
|
+
return parts.length > 1 ? parts[1] : undefined
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static styles = css`
|
|
66
|
+
:host {
|
|
67
|
+
display: block;
|
|
68
|
+
position: relative;
|
|
69
|
+
font-family: Inter, -apple-system, BlinkMacSystemFont, sans-serif;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.panel {
|
|
73
|
+
position: fixed;
|
|
74
|
+
top: 0;
|
|
75
|
+
left: 0;
|
|
76
|
+
right: 0;
|
|
77
|
+
bottom: 0;
|
|
78
|
+
background: rgba(0, 0, 0, 0.5);
|
|
79
|
+
z-index: 1000;
|
|
80
|
+
opacity: 0;
|
|
81
|
+
visibility: hidden;
|
|
82
|
+
transition: all 0.3s ease;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.panel.open {
|
|
86
|
+
opacity: 1;
|
|
87
|
+
visibility: visible;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.panel-content {
|
|
91
|
+
position: absolute;
|
|
92
|
+
top: 0;
|
|
93
|
+
right: 0;
|
|
94
|
+
width: 100%;
|
|
95
|
+
max-width: 400px;
|
|
96
|
+
height: 100%;
|
|
97
|
+
background: white;
|
|
98
|
+
transform: translateX(100%);
|
|
99
|
+
transition: transform 0.3s ease;
|
|
100
|
+
overflow-y: auto;
|
|
101
|
+
padding: 24px;
|
|
102
|
+
box-sizing: border-box;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.panel.open .panel-content {
|
|
106
|
+
transform: translateX(0);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.close-button {
|
|
110
|
+
position: absolute;
|
|
111
|
+
top: 20px;
|
|
112
|
+
right: 20px;
|
|
113
|
+
background: none;
|
|
114
|
+
border: none;
|
|
115
|
+
font-size: 24px;
|
|
116
|
+
cursor: pointer;
|
|
117
|
+
color: #6b7280;
|
|
118
|
+
padding: 4px;
|
|
119
|
+
border-radius: 4px;
|
|
120
|
+
transition: background-color 0.2s;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.close-button:hover {
|
|
124
|
+
background-color: #f3f4f6;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.header {
|
|
128
|
+
display: flex;
|
|
129
|
+
align-items: center;
|
|
130
|
+
justify-content: center;
|
|
131
|
+
margin-bottom: 24px;
|
|
132
|
+
padding-top: 20px;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.header-icon {
|
|
136
|
+
margin-right: 12px;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.header-title {
|
|
140
|
+
font-size: 18px;
|
|
141
|
+
font-weight: 600;
|
|
142
|
+
color: #111827;
|
|
143
|
+
text-align: center;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.section {
|
|
147
|
+
margin-bottom: 20px;
|
|
148
|
+
padding: 16px;
|
|
149
|
+
background: #f9fafb;
|
|
150
|
+
border-radius: 12px;
|
|
151
|
+
border: 1px solid #e5e7eb;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.section-title {
|
|
155
|
+
font-size: 14px;
|
|
156
|
+
font-weight: 600;
|
|
157
|
+
color: #374151;
|
|
158
|
+
margin-bottom: 8px;
|
|
159
|
+
display: flex;
|
|
160
|
+
align-items: center;
|
|
161
|
+
gap: 8px;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.section-content {
|
|
165
|
+
font-size: 14px;
|
|
166
|
+
color: #6b7280;
|
|
167
|
+
word-break: break-all;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.copy-button {
|
|
171
|
+
background: none;
|
|
172
|
+
border: none;
|
|
173
|
+
cursor: pointer;
|
|
174
|
+
padding: 4px;
|
|
175
|
+
border-radius: 4px;
|
|
176
|
+
color: #6b7280;
|
|
177
|
+
transition: background-color 0.2s;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.copy-button:hover {
|
|
181
|
+
background-color: #e5e7eb;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.links-list {
|
|
185
|
+
list-style: none;
|
|
186
|
+
padding: 0;
|
|
187
|
+
margin: 0;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.link-item {
|
|
191
|
+
margin-bottom: 8px;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.link-item:last-child {
|
|
195
|
+
margin-bottom: 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.external-link {
|
|
199
|
+
display: inline-flex;
|
|
200
|
+
align-items: center;
|
|
201
|
+
gap: 6px;
|
|
202
|
+
color: #3b82f6;
|
|
203
|
+
text-decoration: none;
|
|
204
|
+
font-size: 14px;
|
|
205
|
+
padding: 6px 12px;
|
|
206
|
+
border-radius: 6px;
|
|
207
|
+
transition: background-color 0.2s;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.external-link:hover {
|
|
211
|
+
background-color: #eff6ff;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.description {
|
|
215
|
+
line-height: 1.6;
|
|
216
|
+
color: #374151;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.loading-placeholder {
|
|
220
|
+
width: 96px;
|
|
221
|
+
height: 96px;
|
|
222
|
+
background: #f3f4f6;
|
|
223
|
+
border-radius: 16px;
|
|
224
|
+
display: flex;
|
|
225
|
+
align-items: center;
|
|
226
|
+
justify-content: center;
|
|
227
|
+
color: #9ca3af;
|
|
228
|
+
font-size: 32px;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
@media (max-width: 640px) {
|
|
232
|
+
.panel-content {
|
|
233
|
+
max-width: 100%;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
`
|
|
237
|
+
|
|
238
|
+
private _handleClose() {
|
|
239
|
+
this.dispatchEvent(new CustomEvent('close'))
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
private _copyToClipboard(text: string) {
|
|
243
|
+
if (navigator.clipboard) {
|
|
244
|
+
navigator.clipboard.writeText(text)
|
|
245
|
+
// Could dispatch a 'copied' event here for toast notifications
|
|
246
|
+
this.dispatchEvent(new CustomEvent('copied', { detail: { text } }))
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private _renderHeader() {
|
|
251
|
+
const name =
|
|
252
|
+
this._resolvedData?.lsp4TokenName ||
|
|
253
|
+
this._resolvedData?.name ||
|
|
254
|
+
'Digital Asset'
|
|
255
|
+
|
|
256
|
+
return html`
|
|
257
|
+
<div class="header">
|
|
258
|
+
${when(
|
|
259
|
+
this.address,
|
|
260
|
+
() => html`
|
|
261
|
+
<icon-view
|
|
262
|
+
address="${this.address}"
|
|
263
|
+
size="large"
|
|
264
|
+
class="header-icon"
|
|
265
|
+
></icon-view>
|
|
266
|
+
`,
|
|
267
|
+
() => html`
|
|
268
|
+
<div class="loading-placeholder">🪙</div>
|
|
269
|
+
`
|
|
270
|
+
)}
|
|
271
|
+
<div class="header-title">${name}</div>
|
|
272
|
+
</div>
|
|
273
|
+
`
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
private _renderContractAddress() {
|
|
277
|
+
const contractAddress = this._extractBaseAddress(this.address)
|
|
278
|
+
if (!contractAddress) return ''
|
|
279
|
+
|
|
280
|
+
return html`
|
|
281
|
+
<div class="section">
|
|
282
|
+
<div class="section-title">
|
|
283
|
+
📄 Contract Address
|
|
284
|
+
<button
|
|
285
|
+
class="copy-button"
|
|
286
|
+
@click=${() => this._copyToClipboard(contractAddress)}
|
|
287
|
+
title="Copy to clipboard"
|
|
288
|
+
>
|
|
289
|
+
📋
|
|
290
|
+
</button>
|
|
291
|
+
</div>
|
|
292
|
+
<div class="section-content">
|
|
293
|
+
<address-view
|
|
294
|
+
.address=${contractAddress}
|
|
295
|
+
format="truncated"
|
|
296
|
+
></address-view>
|
|
297
|
+
</div>
|
|
298
|
+
</div>
|
|
299
|
+
`
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
private _renderTokenId() {
|
|
303
|
+
const tokenId = this._extractTokenId(this.address)
|
|
304
|
+
if (!tokenId) return ''
|
|
305
|
+
|
|
306
|
+
// Use formattedTokenId if available from resolved data, otherwise use raw tokenId
|
|
307
|
+
const formattedTokenId = (this._resolvedData as any)?.formattedTokenId
|
|
308
|
+
const displayTokenId = formattedTokenId
|
|
309
|
+
? `#${formattedTokenId}` // Formatted gets # prefix
|
|
310
|
+
: tokenId || '' // Raw hex without # prefix
|
|
311
|
+
|
|
312
|
+
return html`
|
|
313
|
+
<div class="section">
|
|
314
|
+
<div class="section-title">
|
|
315
|
+
🏷️ Token ID
|
|
316
|
+
<button
|
|
317
|
+
class="copy-button"
|
|
318
|
+
@click=${() => this._copyToClipboard(tokenId)}
|
|
319
|
+
title="Copy to clipboard"
|
|
320
|
+
>
|
|
321
|
+
📋
|
|
322
|
+
</button>
|
|
323
|
+
</div>
|
|
324
|
+
<div class="section-content">${displayTokenId}</div>
|
|
325
|
+
</div>
|
|
326
|
+
`
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
private _renderDescription() {
|
|
330
|
+
const description = (this._resolvedData as any)?.description
|
|
331
|
+
if (!description) return ''
|
|
332
|
+
|
|
333
|
+
return html`
|
|
334
|
+
<div class="section">
|
|
335
|
+
<div class="section-title">📝 Description</div>
|
|
336
|
+
<div class="section-content description">${description}</div>
|
|
337
|
+
</div>
|
|
338
|
+
`
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
private _renderLinks() {
|
|
342
|
+
const links = (this._resolvedData as any)?.links || []
|
|
343
|
+
if (!links.length) return ''
|
|
344
|
+
|
|
345
|
+
return html`
|
|
346
|
+
<div class="section">
|
|
347
|
+
<div class="section-title">🔗 Links</div>
|
|
348
|
+
<ul class="links-list">
|
|
349
|
+
${repeat(
|
|
350
|
+
links,
|
|
351
|
+
(link: any) => link.url,
|
|
352
|
+
(link: any) => html`
|
|
353
|
+
<li class="link-item">
|
|
354
|
+
<a
|
|
355
|
+
class="external-link"
|
|
356
|
+
href="${link.url}"
|
|
357
|
+
target="_blank"
|
|
358
|
+
rel="noopener noreferrer"
|
|
359
|
+
>
|
|
360
|
+
${link.title || link.url}
|
|
361
|
+
<span>↗</span>
|
|
362
|
+
</a>
|
|
363
|
+
</li>
|
|
364
|
+
`
|
|
365
|
+
)}
|
|
366
|
+
</ul>
|
|
367
|
+
</div>
|
|
368
|
+
`
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
private _renderImages() {
|
|
372
|
+
const images = (this._resolvedData as any)?.images || []
|
|
373
|
+
if (!images.length) return ''
|
|
374
|
+
|
|
375
|
+
return html`
|
|
376
|
+
<div class="section">
|
|
377
|
+
<div class="section-title">🖼️ Images</div>
|
|
378
|
+
<image-list
|
|
379
|
+
address=${this.address}
|
|
380
|
+
image-hint="images"
|
|
381
|
+
size="medium"
|
|
382
|
+
></image-list>
|
|
383
|
+
</div>
|
|
384
|
+
`
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
private _renderAssets() {
|
|
388
|
+
const assets = (this._resolvedData as any)?.assets || []
|
|
389
|
+
if (!assets.length) return ''
|
|
390
|
+
|
|
391
|
+
return html`
|
|
392
|
+
<div class="section">
|
|
393
|
+
<div class="section-title">📦 Assets</div>
|
|
394
|
+
<image-list
|
|
395
|
+
address=${this.address}
|
|
396
|
+
image-hint="assets"
|
|
397
|
+
size="medium"
|
|
398
|
+
></image-list>
|
|
399
|
+
</div>
|
|
400
|
+
`
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
private _handleBackdropClick(e: Event) {
|
|
404
|
+
if (e.target === e.currentTarget) {
|
|
405
|
+
this._handleClose()
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
render() {
|
|
410
|
+
const panelClasses = {
|
|
411
|
+
panel: true,
|
|
412
|
+
open: this.open,
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return html`
|
|
416
|
+
<div class=${classMap(panelClasses)} @click=${this._handleBackdropClick}>
|
|
417
|
+
<div class="panel-content" @click=${(e: Event) => e.stopPropagation()}>
|
|
418
|
+
<button class="close-button" @click=${this._handleClose}>×</button>
|
|
419
|
+
|
|
420
|
+
${this._renderHeader()}
|
|
421
|
+
${this._renderContractAddress()}
|
|
422
|
+
${this._renderTokenId()}
|
|
423
|
+
${this._renderDescription()}
|
|
424
|
+
${this._renderLinks()}
|
|
425
|
+
${this._renderImages()}
|
|
426
|
+
${this._renderAssets()}
|
|
427
|
+
</div>
|
|
428
|
+
</div>
|
|
429
|
+
`
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
declare global {
|
|
434
|
+
interface HTMLElementTagNameMap {
|
|
435
|
+
'info-panel': InfoPanel
|
|
436
|
+
}
|
|
437
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { html, nothing } from 'lit'
|
|
2
|
+
import { property } from 'lit/decorators.js'
|
|
3
|
+
import { safeCustomElement } from '../shared/safe-custom-element'
|
|
4
|
+
import { CoreLitElement } from '../styles'
|
|
5
|
+
import '../shared/load-web-components'
|
|
6
|
+
|
|
7
|
+
export type PermissionLevels = {
|
|
8
|
+
permissionName: string
|
|
9
|
+
type: string
|
|
10
|
+
icon?: string
|
|
11
|
+
isActive: boolean
|
|
12
|
+
isForward?: boolean
|
|
13
|
+
info: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Permissions block card
|
|
18
|
+
*
|
|
19
|
+
* Lit/Web Component equivalent of the provided Vue PermissionsBlock.
|
|
20
|
+
* - Uses Tailwind utility classes for styling
|
|
21
|
+
* - Uses LUKSO web components where applicable (lukso-icon)
|
|
22
|
+
*/
|
|
23
|
+
@safeCustomElement('permissions-block')
|
|
24
|
+
export class PermissionsBlock extends CoreLitElement {
|
|
25
|
+
/** Header icon name */
|
|
26
|
+
@property({ type: String }) icon: string = ''
|
|
27
|
+
|
|
28
|
+
/** Optional action icon name (reserved, not displayed yet) */
|
|
29
|
+
@property({ type: String, attribute: 'action-icon' }) actionIcon: string = ''
|
|
30
|
+
|
|
31
|
+
/** CSS color (e.g., var(--blue-75)) applied to icons */
|
|
32
|
+
@property({ type: String }) color: string = 'var(--neutral-60)'
|
|
33
|
+
|
|
34
|
+
/** Title text */
|
|
35
|
+
@property({ type: String }) title: string = ''
|
|
36
|
+
|
|
37
|
+
/** Description text */
|
|
38
|
+
@property({ type: String }) description: string = ''
|
|
39
|
+
|
|
40
|
+
/** Control identifier used by parent (informational only here) */
|
|
41
|
+
@property({ type: String }) control: string = ''
|
|
42
|
+
|
|
43
|
+
/** Permission levels to render */
|
|
44
|
+
@property({ type: Array }) permissions: PermissionLevels[] = []
|
|
45
|
+
|
|
46
|
+
override render() {
|
|
47
|
+
return html`
|
|
48
|
+
<div
|
|
49
|
+
class="mb-6 p-4 bg-[var(--neutral-100)] border border-[var(--neutral-90)] rounded-lg"
|
|
50
|
+
>
|
|
51
|
+
<div class="flex items-center mb-2">
|
|
52
|
+
${
|
|
53
|
+
this.icon
|
|
54
|
+
? html`<lukso-icon
|
|
55
|
+
name=${this.icon}
|
|
56
|
+
size="x-small"
|
|
57
|
+
color=${this.color}
|
|
58
|
+
></lukso-icon>`
|
|
59
|
+
: nothing
|
|
60
|
+
}
|
|
61
|
+
<div class="ml-2 heading-inter-14-bold">${this.title}</div>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
${
|
|
65
|
+
this.description
|
|
66
|
+
? html`<div class="text-[var(--neutral-40)] paragraph-inter-12-regular">
|
|
67
|
+
${this.description}
|
|
68
|
+
</div>`
|
|
69
|
+
: nothing
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
<div class="h-px w-full bg-[var(--neutral-90)] mt-4"></div>
|
|
73
|
+
|
|
74
|
+
<slot></slot>
|
|
75
|
+
|
|
76
|
+
${(this.permissions || []).map((p) => this.renderPermission(p))}
|
|
77
|
+
</div>
|
|
78
|
+
`
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private renderPermission(p: PermissionLevels) {
|
|
82
|
+
const nameBase = (p.icon || p.permissionName || '').toLowerCase()
|
|
83
|
+
const activeIcon = `${nameBase}-activated`
|
|
84
|
+
const inactiveIcon = `${nameBase}-inactive`
|
|
85
|
+
return html`
|
|
86
|
+
<div class="mt-4 grid grid-cols-[40px,1fr,20px] gap-x-2 items-start">
|
|
87
|
+
<div class="relative w-10 h-10">
|
|
88
|
+
<svg-icon
|
|
89
|
+
class="active absolute bottom-0 opacity-0 z-[99] transition-opacity duration-200 ${
|
|
90
|
+
p.isActive ? 'opacity-100' : ''
|
|
91
|
+
}"
|
|
92
|
+
name=${activeIcon}
|
|
93
|
+
width="40"
|
|
94
|
+
height="40"
|
|
95
|
+
color=${this.color}
|
|
96
|
+
></svg-icon>
|
|
97
|
+
<svg-icon
|
|
98
|
+
class="inactive absolute bottom-0 ${p.isActive ? 'opacity-0' : 'opacity-100'}"
|
|
99
|
+
name=${inactiveIcon}
|
|
100
|
+
width="40"
|
|
101
|
+
height="40"
|
|
102
|
+
color=${this.color}
|
|
103
|
+
></svg-icon>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<div>
|
|
107
|
+
<span class="paragraph-inter-12-semi-bold ">${p.type}</span>
|
|
108
|
+
<div class="paragraph-inter-12-regular">${p.info}</div>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
${
|
|
112
|
+
p.isActive
|
|
113
|
+
? html`<lukso-icon
|
|
114
|
+
name="complete-filled"
|
|
115
|
+
width="20"
|
|
116
|
+
height="20"
|
|
117
|
+
secondary-color="neutral-100"
|
|
118
|
+
color="green-54"
|
|
119
|
+
stroke-width="1.5"
|
|
120
|
+
></lukso-icon>`
|
|
121
|
+
: html`<lukso-icon
|
|
122
|
+
name="cross-outline"
|
|
123
|
+
width="20"
|
|
124
|
+
height="20"
|
|
125
|
+
color="red-65"
|
|
126
|
+
stroke-width="1.5"
|
|
127
|
+
></lukso-icon>`
|
|
128
|
+
}
|
|
129
|
+
</div>
|
|
130
|
+
`
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
declare global {
|
|
135
|
+
interface HTMLElementTagNameMap {
|
|
136
|
+
'permissions-block': PermissionsBlock
|
|
137
|
+
}
|
|
138
|
+
}
|