refactor move home / into vue components (#3498)

This commit is contained in:
dni ⚡ 2025-11-10 14:48:27 +01:00 committed by GitHub
parent c9270bbf7f
commit bd50a3c546
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 491 additions and 740 deletions

View file

@ -1,709 +0,0 @@
{% extends "public.html" %} {% block scripts %}
<style>
:root {
--size: 100px;
--gap: 25px;
}
.btn-fixed-width {
/* width: 45%; */
}
.wrapper {
display: flex;
flex-direction: column;
gap: var(--gap);
margin: auto;
max-width: 100%;
}
.marquee {
display: flex;
overflow: hidden;
user-select: none;
gap: var(--gap);
height: max-content;
mask-image: linear-gradient(
to right,
hsl(0 0% 0% / 0),
hsl(0 0% 0% / 1) 20%,
hsl(0 0% 0% / 1) 80%,
hsl(0 0% 0% / 0)
);
}
.marquee__group {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: space-around;
gap: var(--gap);
min-width: 100%;
animation: scroll-x 60s linear infinite;
}
.marquee:hover .marquee__group {
animation-play-state: paused;
}
.marquee__group div {
width: var(--size);
}
@keyframes scroll-x {
from {
transform: translateX(0);
}
to {
transform: translateX(calc(-100% - var(--gap)));
}
}
</style>
<script src="{{ static_url_for('static', 'js/index.js') }}"></script>
{% endblock %} {% block page_container %}
<q-page-container>
<q-page
class="q-px-md q-py-lg content-center"
:class="{'q-px-lg': $q.screen.gt.xs}"
>
{% block page %}
<div
class="row justify-center items-center"
style="min-height: calc(100vh / 1.618)"
>
<div
class="full-width"
:style="`max-width: ${'{{ LNBITS_CUSTOM_IMAGE }}' ? '850' : '600'}px`"
>
<div class="row q-mb-md">
<div class="col-12">
<div>
<h5
class="q-my-none"
v-if="'{{LNBITS_SHOW_HOME_PAGE_ELEMENTS}}' == 'True'"
>
{{SITE_TITLE}}
</h5>
<template v-if="$q.screen.gt.sm">
<h6
class="q-my-sm"
v-if="'{{LNBITS_SHOW_HOME_PAGE_ELEMENTS}}' == 'True'"
>
{{SITE_TAGLINE}}
</h6>
<p
class="q-my-sm"
v-if="'{{LNBITS_SHOW_HOME_PAGE_ELEMENTS}}' == 'True'"
v-html="formatDescription"
></p>
</template>
<!-- <div
class="gt-sm"
v-html="formatDescription"
v-if="'{{LNBITS_SHOW_HOME_PAGE_ELEMENTS}}' == 'True'"
></div> -->
</div>
</div>
</div>
<div class="row">
<q-badge
v-if="isAccessTokenExpired"
class="q-mx-auto q-mb-md"
color="primary"
rounded
>
<div class="text-h6">
<span v-text="$t('session_has_expired')"></span>
</div>
</q-badge>
<q-card bordered class="full-width q-py-md">
<div class="row">
<div
class="col-12"
:class="{'col-sm-7' : '{{ LNBITS_CUSTOM_IMAGE }}', 'col-lg-6' : '{{ LNBITS_CUSTOM_IMAGE }}'}"
>
{% if lnurl and LNBITS_NEW_ACCOUNTS_ALLOWED and ("user-id-only"
in LNBITS_AUTH_METHODS)%}
<div class="full-height content-center">
<q-card-section>
<div class="text-body1">
<span v-text="$t('claim_desc')"></span>
</div>
</q-card-section>
<q-card-section>
<q-btn
unelevated
color="primary"
@click="processing"
type="a"
href="/lnurlwallet?lightning={{ lnurl }}"
v-text="$t('press_to_claim')"
class="full-width"
></q-btn>
</q-card-section>
</div>
{%else%}
<username-password
v-if="authMethod != 'user-id-only'"
:allowed_new_users="allowedRegister"
:auth-methods="LNBITS_AUTH_METHODS"
:auth-action="authAction"
v-model:user-name="username"
v-model:password_1="password"
v-model:password_2="passwordRepeat"
v-model:reset-key="reset_key"
@login="login"
@register="register"
@reset="reset"
>
<div
class="text-center text-grey-6"
v-if="authAction !== 'reset'"
>
<p
v-if="authAction === 'login' && allowedRegister"
class="q-mb-none"
>
Not registered?
<a
href="#"
class="text-secondary cursor-pointer"
@click.prevent="showRegister('username-password')"
>Create an Account</a
>
</p>
<p
v-else-if="authAction === 'login' && !allowedRegister"
class="q-mb-none"
>
<span v-text="$t('new_user_not_allowed')"></span>
</p>
<p v-else-if="authAction === 'register'" class="q-mb-none">
<span v-text="$t('existing_account_question')"></span>
<a
href="#"
class="text-secondary cursor-pointer q-ml-sm"
@click.prevent="showLogin('username-password')"
v-text="$t('login')"
></a>
</p>
</div>
</username-password>
{% if "user-id-only" in LNBITS_AUTH_METHODS %}
<user-id-only
:allowed_new_users="allowedRegister"
v-model:usr="usr"
v-model:wallet="walletName"
:auth-action="authAction"
:auth-method="authMethod"
@show-login="showLogin"
@show-register="showRegister"
@login-usr="loginUsr"
@create-wallet="createWallet"
>
</user-id-only>
{%endif%} {% endif %}
</div>
<div
class="col-sm-5 col-lg-6 gt-xs"
v-if="'{{ LNBITS_CUSTOM_IMAGE }}'"
>
<div class="full-height flex flex-center q-pa-lg">
<q-img
:src="'{{ LNBITS_CUSTOM_IMAGE }}'"
:ratio="1"
width="250px"
></q-img>
</div>
</div>
</div>
</q-card>
</div>
</div>
<div
v-if="'{{ LNBITS_DENOMINATION }}' == 'sats' && '{{ SITE_TITLE }}' == 'LNbits' && '{{ LNBITS_SHOW_HOME_PAGE_ELEMENTS }}' == 'True'"
class="full-width q-mb-lg q-mt-sm"
>
<div class="flex flex-center q-gutter-md q-py-md">
<q-btn
outline
color="grey"
type="a"
href="https://github.com/lnbits/lnbits"
target="_blank"
rel="noopener noreferrer"
:label="$t('view_github')"
class=""
></q-btn>
<q-btn
outline
color="grey"
type="a"
href="https://demo.lnbits.com/lnurlp/link/fH59GD"
target="_blank"
rel="noopener noreferrer"
:label="$t('donate')"
class=""
></q-btn>
</div>
</div>
{% if AD_SPACE_ENABLED and AD_SPACE %}
<div class="q-pt-md full-width">
<div class="row justify-center q-mb-xl">
<div class="full-width text-center">
<span class="text-uppercase text-grey">{{ AD_SPACE_TITLE }}</span>
</div>
<div class="flex flex-center columm">
{% for ADS in AD_SPACE %} {% set AD = ADS.split(';') %}
<div class="flex flex-center column q-pr-sm">
<a href="{{ AD[0] }}">
<img
v-if="($q.dark.isActive)"
src="{{ AD[1] }}"
style="max-width: 420px"
class="full-width"
/>
<img
v-else
src="{{ AD[2] }}"
style="max-width: 420px"
class="full-width"
/>
</a>
</div>
{% endfor %}
</div>
</div>
</div>
{% endif %}
<div
v-if="'{{ LNBITS_DENOMINATION }}' == 'sats' && '{{ SITE_TITLE }}' == 'LNbits' && '{{ LNBITS_SHOW_HOME_PAGE_ELEMENTS }}' == 'True'"
class="full-width"
>
<div class="wrapper">
<div class="marquee">
<div class="marquee__group">
<div>
<a
href="https://github.com/ElementsProject/lightning"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/cln.png') }}' : '{{ static_url_for('static', 'images/clnl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://github.com/lightningnetwork/lnd"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/lnd.png') }}' : '{{ static_url_for('static', 'images/lnd.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://opennode.com"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/opennode.png') }}' : '{{ static_url_for('static', 'images/opennodel.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://lnpay.co/"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/lnpay.png') }}' : '{{ static_url_for('static', 'images/lnpayl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://github.com/rootzoll/raspiblitz"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/blitz.png') }}' : '{{ static_url_for('static', 'images/blitzl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://start9.com/"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/start9.png') }}' : '{{ static_url_for('static', 'images/start9l.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://getumbrel.com/"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/umbrel.png') }}' : '{{ static_url_for('static', 'images/umbrell.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://mynodebtc.com"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/mynode.png') }}' : '{{ static_url_for('static', 'images/mynodel.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://github.com/shesek/spark-wallet"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/spark.png') }}' : '{{ static_url_for('static', 'images/sparkl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://voltage.cloud"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/voltage.png') }}' : '{{ static_url_for('static', 'images/voltagel.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://breez.technology/sdk/"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/breez.png') }}' : '{{ static_url_for('static', 'images/breezl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://blockstream.com/lightning/greenlight/"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/greenlight.png') }}' : '{{ static_url_for('static', 'images/greenlightl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://getalby.com"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/alby.png') }}' : '{{ static_url_for('static', 'images/albyl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://zbd.gg"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/zbd.png') }}' : '{{ static_url_for('static', 'images/zbdl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://phoenix.acinq.co/server"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/phoenixd.png') }}' : '{{ static_url_for('static', 'images/phoenixdl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://boltz.exchange/"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/boltz.svg') }}' : '{{ static_url_for('static', 'images/boltz.svg') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://www.blink.sv/"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/blink_logo.png') }}' : '{{ static_url_for('static', 'images/blink_logol.png') }}'"
></q-img>
</a>
</div>
<!-- # -->
</div>
<div class="marquee__group">
<div>
<a
href="https://github.com/ElementsProject/lightning"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/cln.png') }}' : '{{ static_url_for('static', 'images/clnl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://github.com/lightningnetwork/lnd"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/lnd.png') }}' : '{{ static_url_for('static', 'images/lnd.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://opennode.com"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/opennode.png') }}' : '{{ static_url_for('static', 'images/opennodel.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://lnpay.co/"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/lnpay.png') }}' : '{{ static_url_for('static', 'images/lnpayl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://github.com/rootzoll/raspiblitz"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/blitz.png') }}' : '{{ static_url_for('static', 'images/blitzl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://start9.com/"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/start9.png') }}' : '{{ static_url_for('static', 'images/start9l.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://getumbrel.com/"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/umbrel.png') }}' : '{{ static_url_for('static', 'images/umbrell.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://mynodebtc.com"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/mynode.png') }}' : '{{ static_url_for('static', 'images/mynodel.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://github.com/shesek/spark-wallet"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/spark.png') }}' : '{{ static_url_for('static', 'images/sparkl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://voltage.cloud"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/voltage.png') }}' : '{{ static_url_for('static', 'images/voltagel.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://breez.technology/sdk/"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/breez.png') }}' : '{{ static_url_for('static', 'images/breezl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://blockstream.com/lightning/greenlight/"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/greenlight.png') }}' : '{{ static_url_for('static', 'images/greenlightl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://getalby.com"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/alby.png') }}' : '{{ static_url_for('static', 'images/albyl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://zbd.gg"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/zbd.png') }}' : '{{ static_url_for('static', 'images/zbdl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://phoenix.acinq.co/server"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/phoenixd.png') }}' : '{{ static_url_for('static', 'images/phoenixdl.png') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://boltz.exchange/"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/boltz.svg') }}' : '{{ static_url_for('static', 'images/boltz.svg') }}'"
></q-img>
</a>
</div>
<div>
<a
href="https://www.blink.sv/"
target="_blank"
rel="noopener noreferrer"
>
<q-img
contain
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/blink_logo.png') }}' : '{{ static_url_for('static', 'images/blink_logol.png') }}'"
></q-img>
</a>
</div>
<!-- # -->
</div>
</div>
</div>
</div>
</div>
{% endblock %}
</q-page>
</q-page-container>
{% endblock %}

View file

@ -42,13 +42,6 @@ async def favicon():
return RedirectResponse(settings.lnbits_qr_logo) return RedirectResponse(settings.lnbits_qr_logo)
@generic_router.get("/", response_class=HTMLResponse)
async def home(request: Request, lightning: str = ""):
return template_renderer().TemplateResponse(
request, "core/index.html", {"lnurl": lightning}
)
@generic_router.get( @generic_router.get(
"/wallet", "/wallet",
response_class=HTMLResponse, response_class=HTMLResponse,
@ -283,6 +276,7 @@ async def index(
) )
@generic_router.get("/")
@generic_router.get("/node/public") @generic_router.get("/node/public")
@generic_router.get("/first_install", dependencies=[Depends(check_first_install)]) @generic_router.get("/first_install", dependencies=[Depends(check_first_install)])
async def index_public(request: Request) -> HTMLResponse: async def index_public(request: Request) -> HTMLResponse:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -215,6 +215,53 @@ body.body--dark .q-drawer {
backdrop-filter: blur(6px); backdrop-filter: blur(6px);
} }
:root {
--size: 100px;
--gap: 25px;
}
.home .btn-fixed-width {
/* width: 45%; */
}
.home .wrapper {
display: flex;
flex-direction: column;
gap: var(--gap);
margin: auto;
max-width: 100%;
}
.home .marquee {
display: flex;
overflow: hidden;
user-select: none;
gap: var(--gap);
height: max-content;
mask-image: linear-gradient(to right, hsla(0, 0%, 0%, 0), hsl(0, 0%, 0%) 20%, hsl(0, 0%, 0%) 80%, hsla(0, 0%, 0%, 0));
}
.home .marquee__group {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: space-around;
gap: var(--gap);
min-width: 100%;
animation: scroll-x 60s linear infinite;
}
.home .marquee:hover .marquee__group {
animation-play-state: paused;
}
.home .marquee__group div {
width: var(--size);
}
@keyframes scroll-x {
from {
transform: translateX(0);
}
to {
transform: translateX(calc(-100% - var(--gap)));
}
}
[v-cloak] { [v-cloak] {
display: none; display: none;
} }

View file

@ -0,0 +1,104 @@
window.app.component('lnbits-home-logos', {
template: '#lnbits-home-logos',
mixins: [window.windowMixin],
data() {
return {
logos: [
{
href: 'https://github.com/ElementsProject/lightning',
lightSrc: '/static/images/clnl.png',
darkSrc: '/static/images/cln.png'
},
{
href: 'https://github.com/lightningnetwork/lnd',
lightSrc: '/static/images/lnd.png',
darkSrc: '/static/images/lnd.png'
},
{
href: 'https://opennode.com',
lightSrc: '/static/images/opennodel.png',
darkSrc: '/static/images/opennode.png'
},
{
href: 'https://lnpay.co/',
lightSrc: '/static/images/lnpayl.png',
darkSrc: '/static/images/lnpay.png'
},
{
href: 'https://github.com/rootzoll/raspiblitz',
lightSrc: '/static/images/blitzl.png',
darkSrc: '/static/images/blitz.png'
},
{
href: 'https://start9.com/',
lightSrc: '/static/images/start9l.png',
darkSrc: '/static/images/start9.png'
},
{
href: 'https://getumbrel.com/',
lightSrc: '/static/images/umbrell.png',
darkSrc: '/static/images/umbrel.png'
},
{
href: 'https://mynodebtc.com',
lightSrc: '/static/images/mynodel.png',
darkSrc: '/static/images/mynode.png'
},
{
href: 'https://github.com/shesek/spark-wallet',
lightSrc: '/static/images/sparkl.png',
darkSrc: '/static/images/spark.png'
},
{
href: 'https://voltage.cloud',
lightSrc: '/static/images/voltagel.png',
darkSrc: '/static/images/voltage.png'
},
{
href: 'https://breez.technology/sdk/',
lightSrc: '/static/images/breezl.png',
darkSrc: '/static/images/breez.png'
},
{
href: 'https://blockstream.com/lightning/greenlight/',
lightSrc: '/static/images/greenlightl.png',
darkSrc: '/static/images/greenlight.png'
},
{
href: 'https://getalby.com',
lightSrc: '/static/images/albyl.png',
darkSrc: '/static/images/alby.png'
},
{
href: 'https://zbd.gg',
lightSrc: '/static/images/zbdl.png',
darkSrc: '/static/images/zbd.png'
},
{
href: 'https://phoenix.acinq.co/server',
lightSrc: '/static/images/phoenixdl.png',
darkSrc: '/static/images/phoenixd.png'
},
{
href: 'https://boltz.exchange/',
lightSrc: '/static/images/boltzl.svg',
darkSrc: '/static/images/boltz.svg'
},
{
href: 'https://www.blink.sv/',
lightSrc: '/static/images/blink_logol.png',
darkSrc: '/static/images/blink_logo.png'
}
]
}
},
computed: {
showLogos() {
return (
this.LNBITS_DENOMINATION == 'sats' &&
this.SITE_TITLE == 'LNbits' &&
this.LNBITS_SHOW_HOME_PAGE_ELEMENTS == true
)
}
}
})

View file

@ -193,6 +193,11 @@ const routes = [
path: '/first_install', path: '/first_install',
name: 'FirstInstall', name: 'FirstInstall',
component: PageFirstInstall component: PageFirstInstall
},
{
path: '/',
name: 'PageHome',
component: PageHome
} }
] ]

View file

@ -1,13 +1,9 @@
window.app = Vue.createApp({ window.PageHome = {
el: '#vue', template: '#page-home',
mixins: [window.windowMixin], mixins: [window.windowMixin],
data() { data() {
return { return {
disclaimerDialog: { lnurl: '',
show: false,
data: {},
description: ''
},
isUserAuthorized: false, isUserAuthorized: false,
authAction: 'login', authAction: 'login',
authMethod: 'username-password', authMethod: 'username-password',
@ -22,11 +18,50 @@ window.app = Vue.createApp({
} }
}, },
computed: { computed: {
showClaimLnurl() {
return (
this.lnurl !== '' &&
this.allowRegister &&
'user-id-only' in this.LNBITS_AUTH_METHODS
)
},
formatDescription() { formatDescription() {
return LNbits.utils.convertMarkdown(this.description) return LNbits.utils.convertMarkdown(this.SITE_DESCRIPTION)
}, },
isAccessTokenExpired() { isAccessTokenExpired() {
return this.$q.cookies.get('is_access_token_expired') return this.$q.cookies.get('is_access_token_expired')
},
allowRegister() {
return this.LNBITS_NEW_ACCOUNTS_ALLOWED
},
// TODO: this makes no sense
hasCustomImage() {
return this.LNBITS_CUSTOM_IMAGE
},
showHomepageElements() {
return this.HOMEPAGE_ELEMENTS_ENABLED
},
siteTitle() {
return this.SITE_TITLE || ''
},
siteTagline() {
return this.SITE_TAGLINE || ''
},
adsEnabled() {
return this.AD_SPACE_ENABLED && this.AD_SPACE && this.AD_SPACE.length > 0
},
adsTitle() {
return this.AD_SPACE_TITLE || ''
},
ads() {
return this.AD_SPACE.map(ad => ad.split(';'))
},
lnbitsBannerEnabled() {
return (
this.LNBITS_DENOMINATION == 'sats' &&
this.SITE_TITLE == 'LNbits' &&
this.LNBITS_SHOW_HOME_PAGE_ELEMENTS == true
)
} }
}, },
methods: { methods: {
@ -101,23 +136,24 @@ window.app = Vue.createApp({
} }
}, },
created() { created() {
this.description = this.SITE_DESCRIPTION
this.allowedRegister = this.LNBITS_NEW_ACCOUNTS_ALLOWED
this.authAction =
!this.allowedRegister ||
Quasar.LocalStorage.getItem('lnbits.disclaimerShown')
? 'login'
: 'register'
this.isUserAuthorized = !!this.$q.cookies.get('is_lnbits_user_authorized') this.isUserAuthorized = !!this.$q.cookies.get('is_lnbits_user_authorized')
const _acccess_cookies_for_safari_refresh_do_not_delete = document.cookie
const _access_cookies_for_safari_refresh_do_not_delete = document.cookie
if (this.isUserAuthorized) { if (this.isUserAuthorized) {
window.location.href = '/wallet' window.location.href = '/wallet'
} }
this.reset_key = new URLSearchParams(window.location.search).get(
'reset_key' const urlParams = new URLSearchParams(window.location.search)
)
this.reset_key = urlParams.get('reset_key')
if (this.reset_key) { if (this.reset_key) {
this.authAction = 'reset' this.authAction = 'reset'
} }
// check if lightning parameters are present in the URL
if (urlParams.has('lightning')) {
this.lnurl = urlParams.get('lightning')
}
} }
}) }

View file

@ -1,6 +1,7 @@
@import 'themes'; @import 'themes';
@import 'borders'; @import 'borders';
@import 'background'; @import 'background';
@import 'home';
[v-cloak] { [v-cloak] {
display: none; display: none;

View file

@ -0,0 +1,60 @@
:root {
--size: 100px;
--gap: 25px;
}
.home {
.btn-fixed-width {
/* width: 45%; */
}
.wrapper {
display: flex;
flex-direction: column;
gap: var(--gap);
margin: auto;
max-width: 100%;
}
.marquee {
display: flex;
overflow: hidden;
user-select: none;
gap: var(--gap);
height: max-content;
mask-image: linear-gradient(
to right,
hsl(0 0% 0% / 0),
hsl(0 0% 0% / 1) 20%,
hsl(0 0% 0% / 1) 80%,
hsl(0 0% 0% / 0)
);
}
.marquee__group {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: space-around;
gap: var(--gap);
min-width: 100%;
animation: scroll-x 60s linear infinite;
}
.marquee:hover .marquee__group {
animation-play-state: paused;
}
.marquee__group div {
width: var(--size);
}
@keyframes scroll-x {
from {
transform: translateX(0);
}
to {
transform: translateX(calc(-100% - var(--gap)));
}
}
}

View file

@ -43,6 +43,7 @@
"js/lnurl.js" "js/lnurl.js"
], ],
"components": [ "components": [
"js/pages/home.js",
"js/pages/extensions_builder.js", "js/pages/extensions_builder.js",
"js/pages/extensions.js", "js/pages/extensions.js",
"js/pages/first-install.js", "js/pages/first-install.js",
@ -66,6 +67,7 @@
"js/components/admin/lnbits-admin-site-customisation.js", "js/components/admin/lnbits-admin-site-customisation.js",
"js/components/admin/lnbits-admin-library.js", "js/components/admin/lnbits-admin-library.js",
"js/components/admin/lnbits-admin-audit.js", "js/components/admin/lnbits-admin-audit.js",
"js/components/lnbits-home-logos.js",
"js/components/lnbits-new-user-wallet.js", "js/components/lnbits-new-user-wallet.js",
"js/components/lnbits-qrcode.js", "js/components/lnbits-qrcode.js",
"js/components/lnbits-qrcode-lnurl.js", "js/components/lnbits-qrcode-lnurl.js",

View file

@ -12,7 +12,8 @@ include('components/admin/notifications.vue') %} {%
include('components/admin/server.vue') %} {% include('components/admin/server.vue') %} {%
include('components/new_user_wallet.vue') %} {% include('components/new_user_wallet.vue') %} {%
include('components/lnbits-footer.vue') %} {% include('components/lnbits-footer.vue') %} {%
include('components/lnbits-header.vue') %} include('components/lnbits-header.vue') %} {%
include('components/lnbits-home-logos.vue') %}
<template id="lnbits-wallet-list"> <template id="lnbits-wallet-list">
<q-list <q-list

View file

@ -0,0 +1,29 @@
<template id="lnbits-home-logos">
<div v-if="showLogos" class="full-width">
<div class="wrapper">
<div class="marquee">
<div class="marquee__group">
<div v-for="logo in logos">
<a :href="logo.url" target="_blank" rel="noopener noreferrer">
<q-img
contain
:src="$q.dark.isActive ? logo.darkSrc : logo.lightSrc"
></q-img>
</a>
</div>
</div>
<!-- Duplicate for seamless looping -->
<div class="marquee__group">
<div v-for="logo in logos">
<a :href="logo.url" target="_blank" rel="noopener noreferrer">
<q-img
contain
:src="$q.dark.isActive ? logo.darkSrc : logo.lightSrc"
></q-img>
</a>
</div>
</div>
</div>
</div>
</div>
</template>

View file

@ -2,4 +2,5 @@
include('pages/audit.vue') %} {% include('pages/wallets.vue') %} {% include('pages/audit.vue') %} {% include('pages/wallets.vue') %} {%
include('pages/users.vue') %} {% include('pages/admin.vue') %} {% include('pages/users.vue') %} {% include('pages/admin.vue') %} {%
include('pages/account.vue') %} {% include('pages/extensions_builder.vue') %} {% include('pages/account.vue') %} {% include('pages/extensions_builder.vue') %} {%
include('pages/extensions.vue') %} {% include('pages/first-install.vue') %} include('pages/extensions.vue') %} {% include('pages/first-install.vue') %} {%
include('pages/home.vue') %}

View file

@ -0,0 +1,178 @@
<template id="page-home">
<div
class="home row justify-center items-center"
style="min-height: calc(100vh / 1.618)"
>
<div
class="full-width"
:style="`max-width: ${hasCustomImage ? '850' : '600'}px`"
>
<div class="row q-mb-md">
<div class="col-12">
<div v-if="showHomepageElements">
<h5 v-text="siteTitle" class="q-my-none"></h5>
<template v-if="$q.screen.gt.sm">
<h6 class="q-my-sm" v-text="siteTagline"></h6>
<p class="q-my-sm" v-html="formatDescription"></p>
</template>
</div>
</div>
</div>
<div class="row">
<q-badge
v-if="isAccessTokenExpired"
class="q-mx-auto q-mb-md"
color="primary"
rounded
>
<div class="text-h6">
<span v-text="$t('session_has_expired')"></span>
</div>
</q-badge>
<q-card bordered class="full-width q-py-md">
<div class="row">
<div
class="col-12"
:class="{'col-sm-7': hasCustomImage, 'col-lg-6': hasCustomImage}"
>
<div v-if="showClaimLnurl" class="full-height content-center">
<q-card-section>
<div class="text-body1">
<span v-text="$t('claim_desc')"></span>
</div>
</q-card-section>
<q-card-section>
<q-btn
unelevated
color="primary"
@click="processing"
type="a"
:href="'/lnurlwallet?lightning=' + lnurl"
v-text="$t('press_to_claim')"
class="full-width"
></q-btn>
</q-card-section>
</div>
<div v-else class="full-height content-center">
<username-password
v-if="authMethod != 'user-id-only'"
:allowed_new_users="allowRegister"
:auth-methods="LNBITS_AUTH_METHODS"
:auth-action="authAction"
v-model:user-name="username"
v-model:password_1="password"
v-model:password_2="passwordRepeat"
v-model:reset-key="reset_key"
@login="login"
@register="register"
@reset="reset"
>
<div
class="text-center text-grey-6"
v-if="authAction !== 'reset'"
>
<p
v-if="authAction === 'login' && allowRegister"
class="q-mb-none"
>
Not registered?
<a
href="#"
class="text-secondary cursor-pointer"
@click.prevent="showRegister('username-password')"
>Create an Account</a
>
</p>
<p
v-else-if="authAction === 'login' && !allowRegister"
class="q-mb-none"
>
<span v-text="$t('new_user_not_allowed')"></span>
</p>
<p v-else-if="authAction === 'register'" class="q-mb-none">
<span v-text="$t('existing_account_question')"></span>
<a
href="#"
class="text-secondary cursor-pointer q-ml-sm"
@click.prevent="showLogin('username-password')"
v-text="$t('login')"
></a>
</p>
</div>
</username-password>
<user-id-only
v-if="authMethod == 'user-id-only'"
:allowed_new_users="allowRegister"
v-model:usr="usr"
v-model:wallet="walletName"
:auth-action="authAction"
:auth-method="authMethod"
@show-login="showLogin"
@show-register="showRegister"
@login-usr="loginUsr"
@create-wallet="createWallet"
>
</user-id-only>
</div>
</div>
<div v-if="hasCustomImage" class="col-sm-5 col-lg-6 gt-xs">
<div class="full-height flex flex-center q-pa-lg">
<q-img :src="hasCustomImage" :ratio="1" width="250px"></q-img>
</div>
</div>
</div>
</q-card>
</div>
</div>
<div v-if="lnbitsBannerEnabled" class="full-width q-mb-lg q-mt-sm">
<div class="flex flex-center q-gutter-md q-py-md">
<q-btn
outline
color="grey"
type="a"
href="https://github.com/lnbits/lnbits"
target="_blank"
rel="noopener noreferrer"
:label="$t('view_github')"
></q-btn>
<q-btn
outline
color="grey"
type="a"
href="https://demo.lnbits.com/lnurlp/link/fH59GD"
target="_blank"
rel="noopener noreferrer"
:label="$t('donate')"
></q-btn>
</div>
</div>
<div v-if="adsEnabled" class="q-pt-md full-width">
<div class="row justify-center q-mb-xl">
<div class="full-width text-center">
<span v-text="adsTitle" class="text-uppercase text-grey"></span>
</div>
<div class="flex flex-center columm">
<div v-for="ad in ads" class="flex flex-center column q-pr-sm">
<a :href="ad[0]">
<img
v-if="$q.dark.isActive"
:src="ad[1]"
style="max-width: 420px"
class="full-width"
/>
<img
v-else
:src="ad[2]"
style="max-width: 420px"
class="full-width"
/>
</a>
</div>
</div>
</div>
</div>
<lnbits-home-logos />
</div>
</template>

View file

@ -95,6 +95,7 @@
"js/lnurl.js" "js/lnurl.js"
], ],
"components": [ "components": [
"js/pages/home.js",
"js/pages/extensions_builder.js", "js/pages/extensions_builder.js",
"js/pages/extensions.js", "js/pages/extensions.js",
"js/pages/first-install.js", "js/pages/first-install.js",
@ -118,6 +119,7 @@
"js/components/admin/lnbits-admin-site-customisation.js", "js/components/admin/lnbits-admin-site-customisation.js",
"js/components/admin/lnbits-admin-library.js", "js/components/admin/lnbits-admin-library.js",
"js/components/admin/lnbits-admin-audit.js", "js/components/admin/lnbits-admin-audit.js",
"js/components/lnbits-home-logos.js",
"js/components/lnbits-new-user-wallet.js", "js/components/lnbits-new-user-wallet.js",
"js/components/lnbits-qrcode.js", "js/components/lnbits-qrcode.js",
"js/components/lnbits-qrcode-lnurl.js", "js/components/lnbits-qrcode-lnurl.js",