feat: Add nostr
This commit is contained in:
parent
754aada478
commit
1b6536d8ae
139
main.py
139
main.py
@ -8,6 +8,7 @@ import render
|
|||||||
import secrets
|
import secrets
|
||||||
import nginx
|
import nginx
|
||||||
import threading
|
import threading
|
||||||
|
import nostr as nostr_module
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
dotenv.load_dotenv()
|
dotenv.load_dotenv()
|
||||||
@ -109,7 +110,8 @@ def site():
|
|||||||
"btn_bg": "#2c54cf",
|
"btn_bg": "#2c54cf",
|
||||||
"btn_fg": "#ffffff",
|
"btn_fg": "#ffffff",
|
||||||
"socials": [],
|
"socials": [],
|
||||||
"address": []
|
"address": [],
|
||||||
|
"nostrs": []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -298,6 +300,104 @@ def publish():
|
|||||||
response.set_cookie('auth', '', expires=0)
|
response.set_cookie('auth', '', expires=0)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@app.route('/nostr')
|
||||||
|
def nostr():
|
||||||
|
if 'auth' not in request.cookies:
|
||||||
|
return redirect('/')
|
||||||
|
auth = request.cookies['auth']
|
||||||
|
|
||||||
|
for i in cookies:
|
||||||
|
if i['cookie'] == auth:
|
||||||
|
# Load site content
|
||||||
|
if os.path.isfile(f'sites/{i["name"]}.json'):
|
||||||
|
with open(f'sites/{i["name"]}.json') as file:
|
||||||
|
data = json.load(file)
|
||||||
|
nostr = []
|
||||||
|
if 'nostr' in data:
|
||||||
|
nostr = data['nostr']
|
||||||
|
|
||||||
|
return render_template('nostr.html',year=datetime.datetime.now().year, domain=i['name'],nostr=nostr)
|
||||||
|
|
||||||
|
response = make_response(redirect('/'))
|
||||||
|
response.set_cookie('auth', '', expires=0)
|
||||||
|
return response
|
||||||
|
|
||||||
|
@app.route('/nostr', methods=['POST'])
|
||||||
|
def nostr_post():
|
||||||
|
if 'auth' not in request.cookies:
|
||||||
|
return redirect('/')
|
||||||
|
auth = request.cookies['auth']
|
||||||
|
|
||||||
|
for i in cookies:
|
||||||
|
if i['cookie'] == auth:
|
||||||
|
# Get site content
|
||||||
|
if os.path.isfile(f'sites/{i["name"]}.json'):
|
||||||
|
with open(f'sites/{i["name"]}.json') as file:
|
||||||
|
data = json.load(file)
|
||||||
|
else:
|
||||||
|
return redirect('/site')
|
||||||
|
|
||||||
|
nostr = []
|
||||||
|
if 'nostr' in data:
|
||||||
|
nostr = data['nostr']
|
||||||
|
|
||||||
|
# Check for new nostr links
|
||||||
|
if 'new-name' in request.form and 'new-pub' in request.form:
|
||||||
|
name = request.form['new-name']
|
||||||
|
pub = request.form['new-pub']
|
||||||
|
id = len(nostr)
|
||||||
|
for link in nostr:
|
||||||
|
if link['name'] == name:
|
||||||
|
link['pub'] = pub
|
||||||
|
data['nostr'] = nostr
|
||||||
|
with open(f'sites/{i["name"]}.json', 'w') as file:
|
||||||
|
json.dump(data, file)
|
||||||
|
return redirect('/nostr')
|
||||||
|
if link['id'] >= id:
|
||||||
|
id = link['id'] + 1
|
||||||
|
|
||||||
|
nostr.append({'name': name, 'pub': pub, 'id': id})
|
||||||
|
|
||||||
|
|
||||||
|
data['nostr'] = nostr
|
||||||
|
with open(f'sites/{i["name"]}.json', 'w') as file:
|
||||||
|
json.dump(data, file)
|
||||||
|
return redirect('/nostr')
|
||||||
|
|
||||||
|
response = make_response(redirect('/'))
|
||||||
|
response.set_cookie('auth', '', expires=0)
|
||||||
|
return response
|
||||||
|
|
||||||
|
@app.route('/nostr/delete/<int:id>')
|
||||||
|
def nostr_delete(id):
|
||||||
|
if 'auth' not in request.cookies:
|
||||||
|
return redirect('/')
|
||||||
|
auth = request.cookies['auth']
|
||||||
|
|
||||||
|
for i in cookies:
|
||||||
|
if i['cookie'] == auth:
|
||||||
|
# Get site content
|
||||||
|
if os.path.isfile(f'sites/{i["name"]}.json'):
|
||||||
|
with open(f'sites/{i["name"]}.json') as file:
|
||||||
|
data = json.load(file)
|
||||||
|
else:
|
||||||
|
return redirect('/site')
|
||||||
|
|
||||||
|
nostr = []
|
||||||
|
if 'nostr' in data:
|
||||||
|
nostr = data['nostr']
|
||||||
|
|
||||||
|
nostr = [i for i in nostr if i['id'] != id]
|
||||||
|
data['nostr'] = nostr
|
||||||
|
with open(f'sites/{i["name"]}.json', 'w') as file:
|
||||||
|
json.dump(data, file)
|
||||||
|
return redirect('/nostr')
|
||||||
|
|
||||||
|
response = make_response(redirect('/'))
|
||||||
|
response.set_cookie('auth', '', expires=0)
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
@app.route('/.well-known/wallets/<path:path>')
|
@app.route('/.well-known/wallets/<path:path>')
|
||||||
def wallets(path):
|
def wallets(path):
|
||||||
# Check if host is in domains
|
# Check if host is in domains
|
||||||
@ -332,6 +432,43 @@ def wallets(path):
|
|||||||
response.headers['Content-Type'] = 'text/plain'
|
response.headers['Content-Type'] = 'text/plain'
|
||||||
return response
|
return response
|
||||||
return render_template('404.html', year=datetime.datetime.now().year), 404
|
return render_template('404.html', year=datetime.datetime.now().year), 404
|
||||||
|
|
||||||
|
@app.route('/.well-known/nostr.json')
|
||||||
|
def nostr_account():
|
||||||
|
# Check if host is in domains
|
||||||
|
if request.host in DOMAINS:
|
||||||
|
# Check if user is logged in
|
||||||
|
if 'auth' not in request.cookies:
|
||||||
|
return redirect(f'https://{DOMAINS[0]}')
|
||||||
|
auth = request.cookies['auth']
|
||||||
|
for i in cookies:
|
||||||
|
if i['cookie'] == auth:
|
||||||
|
# Load site content
|
||||||
|
if os.path.isfile(f'sites/{i["name"]}.json'):
|
||||||
|
with open(f'sites/{i["name"]}.json') as file:
|
||||||
|
data = json.load(file)
|
||||||
|
if 'nostr' in data:
|
||||||
|
nostr = data['nostr']
|
||||||
|
# Return as plain text
|
||||||
|
response = make_response(nostr_module.json(nostr))
|
||||||
|
response.headers['Content-Type'] = 'text/plain'
|
||||||
|
response.headers.add('Access-Control-Allow-Origin', '*')
|
||||||
|
return response
|
||||||
|
|
||||||
|
# Get wallet from domain
|
||||||
|
host = request.host.split(':')[0]
|
||||||
|
|
||||||
|
if os.path.isfile(f'sites/{host}.json'):
|
||||||
|
with open(f'sites/{host}.json') as file:
|
||||||
|
data = json.load(file)
|
||||||
|
if 'nostr' in data:
|
||||||
|
nostr = data['nostr']
|
||||||
|
# Return as plain text
|
||||||
|
response = make_response(nostr_module.json(nostr))
|
||||||
|
response.headers['Content-Type'] = 'text/plain'
|
||||||
|
response.headers.add('Access-Control-Allow-Origin', '*')
|
||||||
|
return response
|
||||||
|
return render_template('404.html', year=datetime.datetime.now().year), 404
|
||||||
|
|
||||||
|
|
||||||
@app.route('/publishing')
|
@app.route('/publishing')
|
||||||
|
29
nostr.py
Normal file
29
nostr.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from base64 import b32decode
|
||||||
|
from base64 import b16encode
|
||||||
|
from bech32 import bech32_decode
|
||||||
|
from bech32 import bech32_encode
|
||||||
|
|
||||||
|
B32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
|
||||||
|
|
||||||
|
def add_padding(base32_len):
|
||||||
|
bits = base32_len * 5
|
||||||
|
padding_size = (8 - (bits % 8)) % 8
|
||||||
|
return padding_size
|
||||||
|
|
||||||
|
def npub_to_hex(npub):
|
||||||
|
hrd, data = bech32_decode(npub)
|
||||||
|
b32_data = [B32[index] for index in data]
|
||||||
|
data_str = "".join(b32_data)
|
||||||
|
data_length = len(data_str)
|
||||||
|
data_str += "=" * add_padding(data_length)
|
||||||
|
decoded_data = b32decode(data_str)
|
||||||
|
b16_encoded_data = b16encode(decoded_data)
|
||||||
|
hex_str = b16_encoded_data.decode("utf-8").lower()
|
||||||
|
return hex_str
|
||||||
|
|
||||||
|
def json(links):
|
||||||
|
names = {}
|
||||||
|
for link in links:
|
||||||
|
names[link['name']] = npub_to_hex(link['pub'])
|
||||||
|
|
||||||
|
return {'names':names}
|
@ -63,7 +63,7 @@ def address_links(addresses,foreground):
|
|||||||
html = ''
|
html = ''
|
||||||
for address in addresses:
|
for address in addresses:
|
||||||
token = address['token'].upper()
|
token = address['token'].upper()
|
||||||
html += f'<a href=".well-known/wallets/{token}" target="_blank">{tokenImage(token,foreground)}</a>'
|
html += f'<a style="margin:5px;" href=".well-known/wallets/{token}" target="_blank">{tokenImage(token,foreground)}</a>'
|
||||||
return html
|
return html
|
||||||
|
|
||||||
def tokenImage(token,foreground):
|
def tokenImage(token,foreground):
|
||||||
|
@ -2,4 +2,5 @@ flask
|
|||||||
python-dotenv
|
python-dotenv
|
||||||
gunicorn
|
gunicorn
|
||||||
requests
|
requests
|
||||||
apscheduler
|
apscheduler
|
||||||
|
bech32
|
@ -5,7 +5,15 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
<title>HNS Links</title>
|
<title>HNS Links</title>
|
||||||
|
<meta name="twitter:title" content="HNS Links">
|
||||||
|
<meta name="twitter:image" content="https://links.hns.au/assets/img/dashboard.png">
|
||||||
|
<meta name="twitter:card" content="summary">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:title" content="HNS Links">
|
||||||
<meta name="description" content="Create a links page for your domain">
|
<meta name="description" content="Create a links page for your domain">
|
||||||
|
<meta property="og:description" content="Create a links page for your domain">
|
||||||
|
<meta property="og:image" content="https://links.hns.au/assets/img/dashboard.png">
|
||||||
|
<meta name="twitter:description" content="Create a links page for your domain">
|
||||||
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
2
templates/assets/css/styles.min.css
vendored
2
templates/assets/css/styles.min.css
vendored
@ -1 +1 @@
|
|||||||
.video-container{position:relative;padding-bottom:56.25%;padding-top:0;height:0;overflow:hidden}.video-container embed,.video-container iframe,.video-container object{position:absolute;top:0;left:0;width:100%;height:100%}.social-icons{color:#313437;background-color:#fff;padding:70px 0}@media (max-width:767px){.social-icons{padding:50px 0}}.social-div{display:flex;justify-content:center;align-items:center}.social-list{max-width:100%;display:flex;list-style:none;gap:2.5rem}@media (max-width:500px){.social-list{gap:1.5rem}}@media (max-width:420px){.social-list{gap:0}}.custom-button{max-width:500px}.addresses{margin-bottom:20px;display:flex;justify-content:center;align-items:center}.social-icons i{color:#757980;margin:0 10px;width:60px;height:60px;border:1px solid #c8ced7;text-align:center;border-radius:50%;line-height:60px;display:inline-block}.social-link a{text-decoration:none;width:4.8rem;height:4.8rem;background-color:#f0f9fe;border-radius:50%;display:flex;justify-content:center;align-items:center;position:relative;z-index:1;border:3px solid #f0f9fe;overflow:hidden}.social-link a::before{content:"";position:absolute;width:100%;height:100%;background:#000;z-index:0;scale:1 0;transform-origin:bottom;transition:scale .5s}.social-link:hover a::before{scale:1 1}.icon{font-size:2rem;color:#011827;transition:.5s;z-index:2}.social-link a:hover .icon{color:#fff;transform:rotateY(360deg)}
|
.video-container{position:relative;padding-bottom:56.25%;padding-top:0;height:0;overflow:hidden}.video-container embed,.video-container iframe,.video-container object{position:absolute;top:0;left:0;width:100%;height:100%}.nostr{margin-top:1em}.social-icons{color:#313437;background-color:#fff;padding:70px 0}@media (max-width:767px){.social-icons{padding:50px 0}}.social-div{display:flex;justify-content:center;align-items:center}.social-list{max-width:100%;display:flex;list-style:none;gap:2.5rem}@media (max-width:500px){.social-list{gap:1.5rem}}@media (max-width:420px){.social-list{gap:0}}.custom-button{max-width:500px}.addresses{margin-bottom:20px;display:flex;justify-content:center;align-items:center}.social-icons i{color:#757980;margin:0 10px;width:60px;height:60px;border:1px solid #c8ced7;text-align:center;border-radius:50%;line-height:60px;display:inline-block}.social-link a{text-decoration:none;width:4.8rem;height:4.8rem;background-color:#f0f9fe;border-radius:50%;display:flex;justify-content:center;align-items:center;position:relative;z-index:1;border:3px solid #f0f9fe;overflow:hidden}.social-link a::before{content:"";position:absolute;width:100%;height:100%;background:#000;z-index:0;scale:1 0;transform-origin:bottom;transition:scale .5s}.social-link:hover a::before{scale:1 1}.icon{font-size:2rem;color:#011827;transition:.5s;z-index:2}.social-link a:hover .icon{color:#fff;transform:rotateY(360deg)}
|
@ -5,7 +5,23 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
<title>HNS Links</title>
|
<title>HNS Links</title>
|
||||||
|
<meta name="twitter:title" content="HNS Links">
|
||||||
|
<meta name="twitter:image" content="https://links.hns.au/assets/img/dashboard.png">
|
||||||
|
<meta name="twitter:card" content="summary">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:title" content="HNS Links">
|
||||||
<meta name="description" content="Create a links page for your domain">
|
<meta name="description" content="Create a links page for your domain">
|
||||||
|
<meta property="og:description" content="Create a links page for your domain">
|
||||||
|
<meta property="og:image" content="https://links.hns.au/assets/img/dashboard.png">
|
||||||
|
<meta name="twitter:description" content="Create a links page for your domain">
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "http://schema.org",
|
||||||
|
"@type": "WebSite",
|
||||||
|
"name": "HNS Links",
|
||||||
|
"url": "https://links.hns.au"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
111
templates/nostr.html
Normal file
111
templates/nostr.html
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html data-bs-theme="light" lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
|
<title>Nostr - HNS Links</title>
|
||||||
|
<meta name="twitter:title" content="HNS Links">
|
||||||
|
<meta name="twitter:image" content="https://links.hns.au/assets/img/dashboard.png">
|
||||||
|
<meta name="twitter:card" content="summary">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:title" content="HNS Links">
|
||||||
|
<meta name="description" content="Create a links page for your domain">
|
||||||
|
<meta property="og:description" content="Create a links page for your domain">
|
||||||
|
<meta property="og:image" content="https://links.hns.au/assets/img/dashboard.png">
|
||||||
|
<meta name="twitter:description" content="Create a links page for your domain">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
<link rel="stylesheet" href="/assets/bootstrap/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&display=swap">
|
||||||
|
<link rel="stylesheet" href="/assets/css/styles.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
|
||||||
|
<script async src="https://umami.woodburn.au/script.js" data-website-id="a165bb1c-eef8-4737-8066-fcd8b4a380bd"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-md sticky-top py-3 navbar-dark" id="mainNav">
|
||||||
|
<div class="container"><a class="navbar-brand d-flex align-items-center" href="/"><img src="/assets/img/favicon.png" width="45px"><span> HNS Links</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-1"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||||
|
<div class="collapse navbar-collapse" id="navcol-1">
|
||||||
|
<ul class="navbar-nav mx-auto"></ul><a class="btn btn-primary shadow" role="button" href="/preview" style="margin-right: 10px;">Preview</a><a class="btn btn-primary shadow" role="button" href="/logout">Logout</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<header class="bg-dark">
|
||||||
|
<div class="container pt-4 pt-xl-5">
|
||||||
|
<div class="row pt-5">
|
||||||
|
<div class="col-md-8 col-xl-6 text-center text-md-start mx-auto">
|
||||||
|
<div class="text-center">
|
||||||
|
<p class="fw-bold text-success mb-2">{{domain}}/</p>
|
||||||
|
<h1 class="fw-bold">Manage your site</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<section>
|
||||||
|
<div style="padding: 1em;padding-bottom: 25px;max-width: 800px;margin: auto;">
|
||||||
|
<form method="post" enctype="multipart/form-data">
|
||||||
|
<h1>Nostr</h1>
|
||||||
|
<div style="margin-bottom: 25px;">
|
||||||
|
<h4>Nostr Links</h4>{% for link in nostr %}
|
||||||
|
<div class='nostr'>
|
||||||
|
<input class="form-control" type="text" style="display: inline-block;width: auto;" value="{{link.name}}" readonly/>
|
||||||
|
<input class="form-control" type="text" style="display: inline-block;width: auto;" value="{{link.pub}}" readonly/>
|
||||||
|
<a class="btn btn-primary" role="button" href="/nostr/delete/{{link.id}}"><svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 24 24" width="1em" fill="currentColor">
|
||||||
|
<path d="M0 0h24v24H0z" fill="none"></path>
|
||||||
|
<path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path>
|
||||||
|
</svg></a>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<div class='nostr'>
|
||||||
|
<span>Link a new nostr profile</span><br>
|
||||||
|
<input class="form-control" type="text" style="display: inline-block;width: auto;" name="new-name" placeholder="User Name" />
|
||||||
|
<input class="form-control" type="text" style="display: inline-block;width: auto;" name="new-pub" placeholder="npub..." />
|
||||||
|
<br><br>
|
||||||
|
<input class="btn btn-primary" type="submit" value="Link" style="margin-right: 20px;" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section></section>
|
||||||
|
<footer class="bg-dark">
|
||||||
|
<div class="container py-4 py-lg-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-sm-4 col-md-3 text-center text-lg-start d-flex flex-column">
|
||||||
|
<h3 class="fs-6 fw-bold">Services</h3>
|
||||||
|
<ul class="list-unstyled">
|
||||||
|
<li><a href="https://hnshosting.au" target="_blank">Wordpress Hosting</a></li>
|
||||||
|
<li><a href="https://firewallet.au" target="_blank">FireWallet</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 col-md-3 text-center text-lg-start d-flex flex-column">
|
||||||
|
<h3 class="fs-6 fw-bold">About</h3>
|
||||||
|
<ul class="list-unstyled">
|
||||||
|
<li><a href="https://hns.au" target="_blank">HNSAU</a></li>
|
||||||
|
<li><a href="https://nathan.woodburn.au" target="_blank">Nathan.Woodburn/</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-3 text-center text-lg-start d-flex flex-column align-items-center order-first align-items-lg-start order-lg-last">
|
||||||
|
<div class="fw-bold d-flex align-items-center mb-2"><span>HNS Links</span></div>
|
||||||
|
<p class="text-muted">Easy to manage links page on Handshake domains</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="text-muted d-flex justify-content-between align-items-center pt-3">
|
||||||
|
<p class="mb-0">Copyright © {{year}} Nathan.Woodburn/</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script src="/assets/js/jquery.min.js"></script>
|
||||||
|
<script src="/assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
<script src="https://auth.varo.domains/v1"></script>
|
||||||
|
<script src="/assets/js/script.min.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -5,6 +5,10 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
<title>{{title}}</title>
|
<title>{{title}}</title>
|
||||||
|
<meta name="twitter:image" content="https://links.hns.au/assets/img/dashboard.png">
|
||||||
|
<meta name="twitter:card" content="summary">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:image" content="https://links.hns.au/assets/img/dashboard.png">
|
||||||
<meta name="twitter:title" content="{{title}}">
|
<meta name="twitter:title" content="{{title}}">
|
||||||
<meta property="og:title" content="{{title}}">
|
<meta property="og:title" content="{{title}}">
|
||||||
<meta name="description" content="{{title}}">
|
<meta name="description" content="{{title}}">
|
||||||
|
@ -5,6 +5,10 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
<title>{{title}}</title>
|
<title>{{title}}</title>
|
||||||
|
<meta name="twitter:image" content="https://links.hns.au/assets/img/dashboard.png">
|
||||||
|
<meta name="twitter:card" content="summary">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:image" content="https://links.hns.au/assets/img/dashboard.png">
|
||||||
<meta name="twitter:title" content="{{title}}">
|
<meta name="twitter:title" content="{{title}}">
|
||||||
<meta property="og:title" content="{{title}}">
|
<meta property="og:title" content="{{title}}">
|
||||||
<meta name="description" content="{{title}}">
|
<meta name="description" content="{{title}}">
|
||||||
|
@ -5,7 +5,15 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
<title>HNS Links</title>
|
<title>HNS Links</title>
|
||||||
|
<meta name="twitter:title" content="HNS Links">
|
||||||
|
<meta name="twitter:image" content="https://links.hns.au/assets/img/dashboard.png">
|
||||||
|
<meta name="twitter:card" content="summary">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:title" content="HNS Links">
|
||||||
<meta name="description" content="Create a links page for your domain">
|
<meta name="description" content="Create a links page for your domain">
|
||||||
|
<meta property="og:description" content="Create a links page for your domain">
|
||||||
|
<meta property="og:image" content="https://links.hns.au/assets/img/dashboard.png">
|
||||||
|
<meta name="twitter:description" content="Create a links page for your domain">
|
||||||
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
|
@ -5,7 +5,15 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
<title>Home - HNS Links</title>
|
<title>Home - HNS Links</title>
|
||||||
|
<meta name="twitter:title" content="HNS Links">
|
||||||
|
<meta name="twitter:image" content="https://links.hns.au/assets/img/dashboard.png">
|
||||||
|
<meta name="twitter:card" content="summary">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:title" content="HNS Links">
|
||||||
<meta name="description" content="Create a links page for your domain">
|
<meta name="description" content="Create a links page for your domain">
|
||||||
|
<meta property="og:description" content="Create a links page for your domain">
|
||||||
|
<meta property="og:image" content="https://links.hns.au/assets/img/dashboard.png">
|
||||||
|
<meta name="twitter:description" content="Create a links page for your domain">
|
||||||
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
<link rel="icon" type="image/png" sizes="600x627" href="/assets/img/favicon.png">
|
||||||
@ -88,7 +96,7 @@
|
|||||||
</div><input class="btn btn-primary" type="submit" value="Save" style="margin-right: 20px;"><a class="btn btn-primary" role="button" href="/publish">Publish</a>
|
</div><input class="btn btn-primary" type="submit" value="Save" style="margin-right: 20px;"><a class="btn btn-primary" role="button" href="/publish">Publish</a>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6" style="text-align: center;">{{preview|safe}}</div>
|
<div class="col-md-6" style="text-align: center;">{{preview|safe}}<a class="btn btn-primary" role="button" href="/nostr" style="margin-top: 1em;">Link Nostr</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user