Compare commits

...

4 Commits

Author SHA1 Message Date
pluja
17b3642f7e Update favicon 2025-05-20 11:27:55 +00:00
pluja
d64268d396 fix logout issue 2025-05-20 11:12:55 +00:00
pluja
9c289753dd fix generate 2025-05-20 11:00:28 +00:00
pluja
8bdbe8ea36 small updates 2025-05-20 10:29:03 +00:00
14 changed files with 102 additions and 56 deletions

View File

@@ -2,3 +2,5 @@ DATABASE_URL="postgresql://kycnot:kycnot@localhost:3399/kycnot?schema=public"
REDIS_URL="redis://localhost:6379" REDIS_URL="redis://localhost:6379"
SOURCE_CODE_URL="https://github.com" SOURCE_CODE_URL="https://github.com"
SITE_URL="https://localhost:4321" SITE_URL="https://localhost:4321"
ONION_ADDRESS="http://kycnotmezdiftahfmc34pqbpicxlnx3jbf5p7jypge7gdvduu7i6qjqd.onion"
I2P_ADDRESS="http://nti3rj4j4disjcm2kvp4eno7otcejbbxv3ggxwr5tpfk4jucah7q.b32.i2p"

View File

@@ -74,6 +74,18 @@ export default defineConfig({
url: true, url: true,
optional: false, optional: false,
}), }),
I2P_ADDRESS: envField.string({
context: 'server',
access: 'public',
url: true,
optional: false,
}),
ONION_ADDRESS: envField.string({
context: 'server',
access: 'public',
url: true,
optional: false,
}),
REDIS_URL: envField.string({ REDIS_URL: envField.string({
context: 'server', context: 'server',

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 566 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 566 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 692 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 566 B

View File

@@ -34,7 +34,7 @@ const Tag = announcement.link ? 'a' : 'div'
target={announcement.link ? '_blank' : undefined} target={announcement.link ? '_blank' : undefined}
rel="noopener noreferrer" rel="noopener noreferrer"
class={cn( class={cn(
'group relative isolate z-50 flex items-center justify-center gap-x-6 overflow-hidden border-b border-zinc-800 bg-black px-6 py-2 focus-visible:outline-none sm:px-3.5', 'group xs:px-6 2xs:px-4 relative isolate z-50 flex items-center justify-center gap-x-2 overflow-hidden border-b border-zinc-800 bg-black px-2 py-2 focus-visible:outline-none sm:gap-x-6 sm:px-3.5',
className className
)} )}
{...props} {...props}
@@ -66,24 +66,27 @@ const Tag = announcement.link ? 'a' : 'div'
</div> </div>
</div> </div>
<div class="flex items-center justify-between gap-x-3 md:justify-center"> <div class={cn('flex items-center justify-between gap-x-3 md:justify-center', typeInfo.classNames.icon)}>
<div class={cn('flex items-center gap-x-3', typeInfo.classNames.icon)}> <Icon name={typeInfo.icon} class={cn('size-5 flex-shrink-0')} />
<Icon name={typeInfo.icon} class={cn('size-5 flex-shrink-0')} /> <span
<span class={cn(
class={cn( 'font-title line-clamp-3 bg-[linear-gradient(90deg,var(--gradient-edge,#FFEBF9)_0%,var(--gradient-center,#8a56cc)_50%,var(--gradient-edge,#FFEBF9)_100%)] bg-clip-text text-sm leading-tight text-pretty text-transparent [&_a]:underline',
'font-title bg-[linear-gradient(90deg,var(--gradient-edge,#FFEBF9)_0%,var(--gradient-center,#8a56cc)_50%,var(--gradient-edge,#FFEBF9)_100%)] bg-clip-text text-sm leading-tight text-transparent [&_a]:underline', typeInfo.classNames.content
typeInfo.classNames.content )}
)} >
> {announcement.content}
{announcement.content} </span>
</span>
</div>
</div> </div>
<div <div
class="text-day-300 group-focus-visible:outline-primary transition-background relative inline-flex h-full min-w-[120px] cursor-pointer items-center justify-center gap-1.5 overflow-hidden rounded-full border border-white/20 bg-black/10 p-[1px] px-3 py-1 text-sm font-medium shadow-sm backdrop-blur-3xl transition-colors group-hover:bg-white/5 group-focus-visible:ring-2 group-focus-visible:ring-blue-500 group-focus-visible:ring-offset-2 group-focus-visible:ring-offset-black/80" class="text-day-300 group-focus-visible:outline-primary transition-background 2xs:px-4 relative inline-flex h-full shrink-0 cursor-pointer items-center justify-center gap-1.5 overflow-hidden rounded-full border border-white/20 bg-black/10 p-[1px] px-1 py-1 text-sm font-medium shadow-sm backdrop-blur-3xl transition-colors group-hover:bg-white/5 group-focus-visible:ring-2 group-focus-visible:ring-blue-500 group-focus-visible:ring-offset-2 group-focus-visible:ring-offset-black/80 sm:min-w-[120px]"
> >
{announcement.linkText} <span class="2xs:inline-block hidden">
<Icon name="ri:arrow-right-line" class="size-4 transition-transform group-hover:translate-x-0.5" /> {announcement.linkText}
</span>
<Icon
name="ri:arrow-right-line"
class="size-4 shrink-0 transition-transform group-hover:translate-x-0.5"
/>
</div> </div>
</Tag> </Tag>

View File

@@ -1,6 +1,7 @@
--- ---
import { Icon } from 'astro-icon/components' import { Icon } from 'astro-icon/components'
import { isInputError, type ActionAccept, type ActionClient } from 'astro:actions' import { isInputError, type ActionAccept, type ActionClient } from 'astro:actions'
import { Image } from 'astro:assets'
import { CAPTCHA_LENGTH, generateCaptcha } from '../lib/captcha' import { CAPTCHA_LENGTH, generateCaptcha } from '../lib/captcha'
import { cn } from '../lib/cn' import { cn } from '../lib/cn'

View File

@@ -1,6 +1,6 @@
--- ---
import { Icon } from 'astro-icon/components' import { Icon } from 'astro-icon/components'
import QRCode from 'qrcode' import * as QRCode from 'qrcode'
import { cn } from '../lib/cn' import { cn } from '../lib/cn'
@@ -26,7 +26,7 @@ function getAddressURI(address: string, cryptoName: string) {
} }
const qrCodeDataURL = await QRCode.toDataURL(getAddressURI(address, cryptoName), { const qrCodeDataURL = await QRCode.toDataURL(getAddressURI(address, cryptoName), {
width: 128, width: 256,
margin: 1, margin: 1,
color: { color: {
dark: '#ffffff', dark: '#ffffff',
@@ -41,13 +41,18 @@ const qrCodeDataURL = await QRCode.toDataURL(getAddressURI(address, cryptoName),
<Icon name={cryptoIcon} class="size-6 text-white" /> <Icon name={cryptoIcon} class="size-6 text-white" />
<span class="font-title text-base font-semibold text-white">{cryptoName}</span> <span class="font-title text-base font-semibold text-white">{cryptoName}</span>
</div> </div>
<p class="px-7 font-mono text-base leading-snug tracking-wide break-all text-white"> <p
<span class="cursor-pointer px-7 font-mono text-base leading-snug tracking-wide break-all text-white select-all"
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>` address.length > 12
: `<span class="font-bold">${address}</span>`} ? [
/> <span class="mr-0.5 font-bold text-green-500">{address.substring(0, 6)}</span>,
address.substring(6, address.length - 6),
<span class="ml-0.5 font-bold text-green-500">{address.substring(address.length - 6)}</span>,
]
: address
}
</p> </p>
</div> </div>
<img <img
@@ -55,6 +60,6 @@ const qrCodeDataURL = await QRCode.toDataURL(getAddressURI(address, cryptoName),
alt={`${cryptoName} QR code`} alt={`${cryptoName} QR code`}
width="128" width="128"
height="128" height="128"
class="mr-4 hidden size-36 rounded sm:block" class="mr-4 hidden size-32 rounded sm:block"
/> />
</div> </div>

View File

@@ -1,6 +1,6 @@
--- ---
import { Icon } from 'astro-icon/components' import { Icon } from 'astro-icon/components'
import { SOURCE_CODE_URL } from 'astro:env/server' import { SOURCE_CODE_URL, I2P_ADDRESS, ONION_ADDRESS } from 'astro:env/server'
import { cn } from '../lib/cn' import { cn } from '../lib/cn'
@@ -11,10 +11,22 @@ type Props = HTMLAttributes<'footer'>
const links = [ const links = [
{ {
href: SOURCE_CODE_URL, href: SOURCE_CODE_URL,
label: 'Source Code', label: 'Code',
icon: 'ri:git-repository-line', icon: 'ri:git-repository-line',
external: true, external: true,
}, },
{
href: ONION_ADDRESS,
label: 'Tor',
icon: 'onion',
external: true,
},
{
href: I2P_ADDRESS,
label: 'I2P',
icon: 'i2p',
external: true,
},
{ {
href: '/about', href: '/about',
label: 'About', label: 'About',

View File

@@ -159,17 +159,15 @@ const splashText = showSplashText ? sample(splashTexts) : null
<Icon name="ri:user-shared-2-line" class="size-4" /> <Icon name="ri:user-shared-2-line" class="size-4" />
</a> </a>
) : ( ) : (
DEPLOYMENT_MODE !== 'production' && ( <a
<a href="/account/logout"
href="/account/logout" data-astro-prefetch="tap"
data-astro-prefetch="tap" class="xs:px-3 2xs:px-2 last:xs:-mr-3 last:2xs:-mr-2 flex h-full items-center px-1 text-sm text-stone-100 transition-colors last:-mr-1 hover:text-stone-200"
class="xs:px-3 2xs:px-2 last:xs:-mr-3 last:2xs:-mr-2 flex h-full items-center px-1 text-sm text-stone-100 transition-colors last:-mr-1 hover:text-stone-200" transition:name="header-logout-link"
transition:name="header-logout-link" aria-label="Logout"
aria-label="Logout" >
> <Icon name="ri:logout-box-r-line" class="size-4" />
<Icon name="ri:logout-box-r-line" class="size-4" /> </a>
</a>
)
)} )}
</> </>
) : ( ) : (

View File

@@ -14,4 +14,7 @@ export const splashTexts: string[] = [
'Ditch the gatekeepers.', 'Ditch the gatekeepers.',
'Own your identity.', 'Own your identity.',
'Financial privacy matters.', 'Financial privacy matters.',
'Surveillance is the enemy of the soul.',
'Privacy is freedom.',
'Privacy is the freedom to try things out.',
] ]

View File

@@ -202,12 +202,10 @@ If you like this project, you can **support** it through these methods:
## Contact ## Contact
You can contact via direct chat or via email. You can contact via direct chat:
- [SimpleX Chat](https://simplex.chat/contact#/?v=2&smp=smp%3A%2F%2F0YuTwO05YJWS8rkjn9eLJDjQhFKvIYd8d4xG8X1blIU%3D%40smp8.simplex.im%2FcgKHYUYnpAIVoGb9lxb0qEMEpvYIvc1O%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAIW_JSq8wOsLKG4Xv4O54uT2D_l8MJBYKQIFj1FjZpnU%253D%26srv%3Dbeccx4yfxxbvyhqypaavemqurytl6hozr47wfc7uuecacjqdvwpw2xid.onion) - [SimpleX Chat](https://simplex.chat/contact#/?v=2&smp=smp%3A%2F%2F0YuTwO05YJWS8rkjn9eLJDjQhFKvIYd8d4xG8X1blIU%3D%40smp8.simplex.im%2FcgKHYUYnpAIVoGb9lxb0qEMEpvYIvc1O%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAIW_JSq8wOsLKG4Xv4O54uT2D_l8MJBYKQIFj1FjZpnU%253D%26srv%3Dbeccx4yfxxbvyhqypaavemqurytl6hozr47wfc7uuecacjqdvwpw2xid.onion)
- If you use ProtonMail or Tutanota, you can have E2E encrypted communications with us directly. We also offer a [PGP Key](/pgp). Otherwise, we recommend reaching out via SimpleX chat for encrypted communications.
## Disclaimer ## Disclaimer

View File

@@ -336,6 +336,14 @@ const makeSortUrl = (slug: NonNullable<(typeof filters)['sort-by']>) => {
> >
<Icon name="ri:edit-line" class="size-4" /> <Icon name="ri:edit-line" class="size-4" />
</Tooltip> </Tooltip>
<Tooltip
as="a"
href={`/u/${user.name}`}
class="inline-flex items-center rounded-md border border-green-500/50 bg-green-500/20 px-1 py-1 text-xs text-green-400 transition-colors hover:bg-green-500/30"
text="Public profile"
>
<Icon name="ri:global-line" class="size-4" />
</Tooltip>
</div> </div>
</td> </td>
</tr> </tr>