donation component
This commit is contained in:
@@ -2,75 +2,50 @@
|
||||
import { Icon } from 'astro-icon/components'
|
||||
import { Markdown } from 'astro-remote'
|
||||
|
||||
import type { AnnouncementType } from '@prisma/client'
|
||||
import { getAnnouncementTypeInfo } from '../constants/announcementTypes'
|
||||
import { cn } from '../lib/cn'
|
||||
|
||||
export type Announcement = {
|
||||
id: number
|
||||
title: string
|
||||
content: string
|
||||
type: AnnouncementType
|
||||
startDate: Date
|
||||
endDate: Date | null
|
||||
isActive: boolean
|
||||
}
|
||||
import type { Prisma } from '@prisma/client'
|
||||
|
||||
export type Props = {
|
||||
announcements: Announcement[]
|
||||
type Props = {
|
||||
announcements:
|
||||
| Prisma.AnnouncementGetPayload<{
|
||||
select: {
|
||||
id: true
|
||||
title: true
|
||||
content: true
|
||||
type: true
|
||||
startDate: true
|
||||
endDate: true
|
||||
isActive: true
|
||||
}
|
||||
}>[]
|
||||
| null
|
||||
| undefined
|
||||
}
|
||||
|
||||
const { announcements } = Astro.props
|
||||
|
||||
// Get icon and class based on announcement type
|
||||
const getTypeInfo = (type: AnnouncementType) => {
|
||||
switch (type) {
|
||||
case 'INFO':
|
||||
return {
|
||||
icon: 'ri:information-line',
|
||||
containerClass: 'bg-blue-900/40 border-blue-500/30',
|
||||
titleClass: 'text-blue-400',
|
||||
contentClass: 'text-blue-300',
|
||||
}
|
||||
case 'WARNING':
|
||||
return {
|
||||
icon: 'ri:alert-line',
|
||||
containerClass: 'bg-yellow-900/40 border-yellow-500/30',
|
||||
titleClass: 'text-yellow-400',
|
||||
contentClass: 'text-yellow-300',
|
||||
}
|
||||
case 'ALERT':
|
||||
return {
|
||||
icon: 'ri:error-warning-line',
|
||||
containerClass: 'bg-red-900/40 border-red-500/30',
|
||||
titleClass: 'text-red-400',
|
||||
contentClass: 'text-red-300',
|
||||
}
|
||||
default:
|
||||
return {
|
||||
icon: 'ri:information-line',
|
||||
containerClass: 'bg-blue-900/40 border-blue-500/30',
|
||||
titleClass: 'text-blue-400',
|
||||
contentClass: 'text-blue-300',
|
||||
}
|
||||
}
|
||||
}
|
||||
---
|
||||
|
||||
{
|
||||
announcements.length > 0 && (
|
||||
!!announcements && announcements.length > 0 && (
|
||||
<div class="mb-4 flex flex-col items-center space-y-1">
|
||||
{announcements.map((announcement) => {
|
||||
const typeInfo = getTypeInfo(announcement.type)
|
||||
const typeInfo = getAnnouncementTypeInfo(announcement.type)
|
||||
|
||||
return (
|
||||
<div
|
||||
class={`flex flex-row items-center rounded border ${typeInfo.containerClass} mx-auto w-auto max-w-full px-3 py-2`}
|
||||
class={cn(
|
||||
'mx-auto flex w-auto max-w-full flex-row items-center rounded border px-3 py-2',
|
||||
typeInfo.classNames.container
|
||||
)}
|
||||
>
|
||||
<Icon name={typeInfo.icon} class={`size-4 flex-shrink-0 ${typeInfo.titleClass} mr-2`} />
|
||||
<Icon name={typeInfo.icon} class={cn('mr-2 size-4 flex-shrink-0', typeInfo.classNames.title)} />
|
||||
<div class="flex min-w-0 flex-col">
|
||||
<span class={`text-sm leading-tight font-bold ${typeInfo.titleClass} truncate`}>
|
||||
<span class={cn('truncate text-sm leading-tight font-bold', typeInfo.classNames.title)}>
|
||||
{announcement.title}
|
||||
</span>
|
||||
<span class={`text-xs ${typeInfo.contentClass} truncate leading-snug [&_a]:underline`}>
|
||||
<span class={cn('truncate text-xs leading-snug [&_a]:underline', typeInfo.classNames.content)}>
|
||||
<Markdown content={announcement.content} />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
60
web/src/components/DonationAddress.astro
Normal file
60
web/src/components/DonationAddress.astro
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
import { Icon } from 'astro-icon/components'
|
||||
import QRCode from 'qrcode'
|
||||
|
||||
import { cn } from '../lib/cn'
|
||||
|
||||
type Props = {
|
||||
cryptoName: string
|
||||
cryptoIcon: string
|
||||
address: string
|
||||
className?: string
|
||||
}
|
||||
|
||||
const { cryptoName, cryptoIcon, address, className } = Astro.props
|
||||
|
||||
function getAddressURI(address: string, cryptoName: string) {
|
||||
if (cryptoName.toLowerCase() === 'monero') {
|
||||
return `monero:${address}?tx_description=KYCnot.me%20Donation`
|
||||
}
|
||||
|
||||
if (cryptoName.toLowerCase() === 'bitcoin') {
|
||||
return `bitcoin:${address}?label=KYCnot.me%20Donation`
|
||||
}
|
||||
|
||||
return address
|
||||
}
|
||||
|
||||
const qrCodeDataURL = await QRCode.toDataURL(getAddressURI(address, cryptoName), {
|
||||
width: 128,
|
||||
margin: 1,
|
||||
color: {
|
||||
dark: '#ffffff',
|
||||
light: '#171721',
|
||||
},
|
||||
})
|
||||
---
|
||||
|
||||
<div class={cn('bg-night-800 border-night-600 flex items-center gap-2 rounded-lg border px-3', className)}>
|
||||
<div class="flex flex-1 flex-col gap-1 py-3">
|
||||
<div class="flex items-center gap-2 px-4 pt-3">
|
||||
<Icon name={cryptoIcon} class="size-6 text-white" />
|
||||
<span class="font-title text-base font-semibold text-white">{cryptoName}</span>
|
||||
</div>
|
||||
<p class="px-7 font-mono text-base leading-snug tracking-wide break-all text-white">
|
||||
<span
|
||||
class="cursor-pointer select-all"
|
||||
set:html={address.length > 12
|
||||
? `<span class="font-bold mr-0.5 text-green-500">${address.substring(0, 6)}</span>${address.substring(6, address.length - 6)}<span class="font-bold ml-0.5 text-green-500">${address.substring(address.length - 6)}</span>`
|
||||
: `<span class="font-bold">${address}</span>`}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
<img
|
||||
src={qrCodeDataURL}
|
||||
alt={`${cryptoName} QR code`}
|
||||
width="128"
|
||||
height="128"
|
||||
class="mr-4 hidden size-36 rounded sm:block"
|
||||
/>
|
||||
</div>
|
||||
Reference in New Issue
Block a user