revamping frontend

master
lza_menace 2 years ago
parent fbf51acab6
commit d937a12317

@ -11,6 +11,9 @@ setup: ## Establish local environment with dependencies installed
.venv/bin/pip install -r requirements.txt .venv/bin/pip install -r requirements.txt
mkdir -p data/uploads mkdir -p data/uploads
setup-dev: ## Install development dependencies
.venv/bin/pip install -r requirements-dev.txt
build: ## Build containers build: ## Build containers
docker-compose build docker-compose build

@ -1,4 +1,6 @@
import click import click
import lorem
from os import path, makedirs from os import path, makedirs
from urllib.request import urlopen from urllib.request import urlopen
@ -28,7 +30,23 @@ def cli(app):
'wallet': '77toDDnVmSrWMZ5tS17UWXcxQVkD6LtNSArVwzsWdE176oDbYtPTiAqExjDZWGE5KwKPY7Kd1BcWYfCnJuL2RfcqA1gzoEj', 'wallet': '77toDDnVmSrWMZ5tS17UWXcxQVkD6LtNSArVwzsWdE176oDbYtPTiAqExjDZWGE5KwKPY7Kd1BcWYfCnJuL2RfcqA1gzoEj',
'art': [ 'art': [
'https://www.monerochan.art/commissions/hammock.png', 'https://www.monerochan.art/commissions/hammock.png',
'https://www.monerochan.art/commissions/assaultrifle.png' 'https://www.monerochan.art/commissions/assaultrifle.png',
'https://www.monerochan.art/thumbnails/vtubing.png',
'https://www.monerochan.art/commissions/ribbons.jpg',
'https://www.monerochan.art/commissions/mining.jpg',
'https://www.monerochan.art/commissions/wownerochan_headpat.png',
'https://www.monerochan.art/commissions/wownerochan.jpg'
]
},
'gemini': {
'wallet': '78TanhCTvw4V8HkY3vD49A5EiyeGCzCHQUm59sByukTcffZPf3QHoK8PDg8WpMUc6VGwqxTu65HvwCUfB2jZutb6NKpjArk',
'art': [
'https://www.monerochan.art/commissions/cheerleader.jpg',
'https://www.monerochan.art/commissions/maidnero-chan.png',
'https://www.monerochan.art/commissions/dandelion.png',
'https://www.monerochan.art/commissions/volleyball_1.jpg',
'https://www.monerochan.art/commissions/volleyball_2.jpg',
'https://www.monerochan.art/commissions/virgin_killer.png'
] ]
} }
} }
@ -59,8 +77,8 @@ def cli(app):
creator=_user, creator=_user,
image=bn, image=bn,
approved=True, approved=True,
title=f'i made {bn}', title=lorem.sentence(),
description='' description=lorem.sentence()
) )
artwork.save() artwork.save()
click.echo(f'[+] Created artwork {artwork.id} for {bn}') click.echo(f'[+] Created artwork {artwork.id} for {bn}')

@ -25,7 +25,7 @@ class User(pw.Model):
register_date = pw.DateTimeField(default=datetime.utcnow) register_date = pw.DateTimeField(default=datetime.utcnow)
last_login_date = pw.DateTimeField(default=datetime.utcnow) last_login_date = pw.DateTimeField(default=datetime.utcnow)
handle = pw.CharField(unique=True) handle = pw.CharField(unique=True)
wallet_address = pw.CharField(unique=True) wallet_address = pw.CharField(unique=True, null=False)
challenge = pw.CharField(default=gen_challenge) challenge = pw.CharField(default=gen_challenge)
is_admin = pw.BooleanField(default=False) is_admin = pw.BooleanField(default=False)
is_mod = pw.BooleanField(default=False) is_mod = pw.BooleanField(default=False)
@ -82,7 +82,6 @@ class Artwork(pw.Model):
id = pw.AutoField() id = pw.AutoField()
creator = pw.ForeignKeyField(User) creator = pw.ForeignKeyField(User)
image = pw.CharField() image = pw.CharField()
thumbnail = pw.CharField(null=True)
upload_date = pw.DateTimeField(default=datetime.utcnow) upload_date = pw.DateTimeField(default=datetime.utcnow)
last_edit_date = pw.DateTimeField(default=datetime.utcnow) last_edit_date = pw.DateTimeField(default=datetime.utcnow)
approved = pw.BooleanField(default=False) approved = pw.BooleanField(default=False)
@ -90,6 +89,10 @@ class Artwork(pw.Model):
title = pw.CharField() title = pw.CharField()
description = pw.TextField(null=True) description = pw.TextField(null=True)
@property
def thumbnail(self):
return f'thumbnail-{self.image}'
def generate_thumbnail(self): def generate_thumbnail(self):
is_gif = self.image.endswith('.gif') is_gif = self.image.endswith('.gif')
_t = f'thumbnail-{self.image}' _t = f'thumbnail-{self.image}'
@ -113,7 +116,7 @@ class Artwork(pw.Model):
_image.save(t, format=image.format, save_all=True, append_images=list(_frames), disposal=2) _image.save(t, format=image.format, save_all=True, append_images=list(_frames), disposal=2)
else: else:
image.thumbnail(size, Image.ANTIALIAS) image.thumbnail(size, Image.ANTIALIAS)
image.save(t, format=image.format, quality=75) image.save(t, format=image.format)
image.close() image.close()
self.thumbnail = _t self.thumbnail = _t
self.save() self.save()

@ -6,6 +6,10 @@ from nerochan.models import Artwork, User
bp = Blueprint('artwork', 'artwork', url_prefix='/artwork') bp = Blueprint('artwork', 'artwork', url_prefix='/artwork')
@bp.route('')
def list():
return 'show all artwork'
@bp.route('/<int:id>') @bp.route('/<int:id>')
def show(id): def show(id):
artwork = Artwork.get_or_none(id) artwork = Artwork.get_or_none(id)

@ -12,11 +12,11 @@ bp = Blueprint('main', 'main')
def index(): def index():
users = User.select().where( users = User.select().where(
User.is_approved == True User.is_approved == True
).order_by(User.register_date.desc()) ).order_by(User.register_date.desc()).limit(10)
artwork = Artwork.select().where( artwork = Artwork.select().where(
Artwork.approved == True, Artwork.approved == True,
Artwork.hidden == False Artwork.hidden == False
).order_by(Artwork.upload_date.desc()) ).order_by(Artwork.upload_date.desc()).limit(10)
feed = { feed = {
'users': users, 'users': users,
'artwork': artwork 'artwork': artwork

@ -0,0 +1,122 @@
body {
background-color: black;
color: white;
font-family: monospace;
}
a, a:visited {
color: white;
}
.artworkLink img {
border-radius: 2px;
margin: 1em;
}
.artworkLink {
text-decoration: none;
}
.artworkDescription {
margin-top: 1em;
}
hr {
margin-top: 0;
}
input[type="text"] {
color: black;
}
.walletAddress {
overflow-wrap: anywhere;
user-select: all;
}
.button-primary {
background-color: #ff6600 !important;
border: 1px solid #ff6600 !important;
transition: all .3s ease;
}
.button-primary:hover {
background-color: #4c4c4c !important;
color: white !important;
border: 1px solid #4c4c4c !important;
transition: all .3s ease;
}
.no-margin {
margin: 0;
}
.navbar + .docs-section {
border-top-width: 0;
}
.navbar {
margin-bottom: 2em;
}
.navbar, .navbar-spacer {
display: block;
width: 100%;
height: 6.5rem;
z-index: 99;
}
.navbar-spacer {
display: none;
}
.navbar > .container {
width: 100%;
}
.navbar-list {
list-style: none;
margin-bottom: 0;
}
.navbar-item {
position: relative;
float: left;
margin-bottom: 0;
}
.navbar-link {
text-transform: uppercase;
font-size: 11px;
font-weight: 600;
letter-spacing: .2rem;
margin-right: 35px;
text-decoration: none;
line-height: 6.5rem;
color: #222;
transition: all .2s ease;
}
.navbar-link:hover {
color: #ff6600;
transition: all .2s ease;
}
.navbar-link.active {
color: #33C3F0;
}
.has-docked-nav .navbar {
position: fixed;
top: 0;
left: 0;
}
.has-docked-nav .navbar-spacer {
display: block;
}
/* Re-overiding the width 100% declaration to match size of % based container */
.has-docked-nav .navbar > .container {
width: 80%;
}

@ -2,7 +2,18 @@
{% block content %} {% block content %}
<h1>about</h1> <div class="container">
<p>nerochan, uwu</p> <div class="row">
<h1>about</h1>
<p>
This site is dedicated to the Monero communities' favorite e-girl, <a href="https://monerochan.art" target="_blank">Monero-Chan</a>.
</p>
<p>
Made with <3 by <a href="https://twitter.com/lza_menace" target="_blank">@lza_menace</a>.
Send him a tip: <span class="walletAddress">49awrmn61ExDUZrV5wJxMM54fxVzHABUYUBNBskLJbxzVwk1KqfrFvdcPNK6RKY2qyfGbcpXP3mbofmnMmFKiFHSCB6jLFA</span>
</p>
</div>
</div>
{% endblock %} {% endblock %}

@ -5,11 +5,57 @@
{% set img = url_for('main.uploaded_file', filename=artwork.image) %} {% set img = url_for('main.uploaded_file', filename=artwork.image) %}
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<h2>{{ artwork.title }}</h2> <h2 class="no-margin"><strong>{{ artwork.title }}</strong></h2>
<p>{{ artwork.creator.handle }}</p> <h6 class="no-margin">
<a href="{{ img }}"> Posted by <a href="{{ url_for('user.show', handle=artwork.creator.handle) }}">{{ artwork.creator.handle }}</a> - {{ artwork.upload_date | humanize }}
<img src="{{ img }}" width="450px"> </h6>
</a> <p class="artworkDescription">{{ artwork.description }}</p>
</div>
<hr>
<div class="row">
<div class="column one-half">
<a href="{{ img }}">
<img src="{{ img }}" width="100%">
</a>
</div>
<div class="column one-half">
<h5>Send a Tip</h5>
<p class="walletAddress">{{ artwork.creator.wallet_address }}</p>
<form method="get">
<div class="row">
<div class="six columns">
<label for="txID">TX ID</label>
<input class="u-full-width" type="text" placeholder="..." id="txID" name="txID">
</div>
<div class="six columns">
<label for="txKey">TX Key</label>
<input class="u-full-width" type="text" placeholder="..." id="txKey" name="txKey">
</div>
</div>
<input class="button-primary" type="submit" value="Submit">
</form>
<table class="u-full-width">
<thead>
<tr>
<th>TXID</th>
<th>XMR</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<tr>
<td>e599...5429</td>
<td>.05</td>
<td>3 days ago</td>
</tr>
<tr>
<td>681a...e264</td>
<td>.25</td>
<td>28 days ago</td>
</tr>
</tbody>
</table>
</div>
</div> </div>
</div> </div>

@ -2,10 +2,16 @@
{% block content %} {% block content %}
<h2>Challenge</h2> <div class="container">
<p>Handle: {{ user.handle }}</p> <div class="row">
<p>Challenge: {{ user.challenge }}</p> <h1>challenge</h1>
<p>Wallet Address: {{ user.wallet_address }}</p> <p>Handle: {{ user.handle }}</p>
{% include 'includes/form.html' %} <p>Challenge: <span class="walletAddress">{{ user.challenge }}</span></p>
<p>Wallet Address: <span class="walletAddress">{{ user.wallet_address }}</span></p>
{% include 'includes/form.html' %}
</div>
</div>
{% endblock %} {% endblock %}

@ -2,7 +2,13 @@
{% block content %} {% block content %}
<h2>Login</h2> <div class="container">
{% include 'includes/form.html' %} <div class="row">
<h1>login</h1>
{% include 'includes/form.html' %}
<a href="{{ url_for('auth.register') }}">Register</a>
</div>
</div>
{% endblock %} {% endblock %}

@ -2,7 +2,13 @@
{% block content %} {% block content %}
<h2>Register</h2>
{% include 'includes/form.html' %} <div class="container">
<div class="row">
<h1>register</h1>
{% include 'includes/form.html' %}
<a href="{{ url_for('auth.login') }}">Login</a>
</div>
</div>
{% endblock %} {% endblock %}

@ -1,18 +1,9 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html>
{% include 'includes/head.html' %} {% include 'includes/head.html' %}
<body style="background-color: black; color: white;"> <body>
{% include 'includes/header.html' %} {% include 'includes/navbar.html' %}
{% block content %}{% endblock %} {% block content %}{% endblock %}
{% include 'includes/debug.html' %} {% include 'includes/debug.html' %}
<style>
body {
background-color: black;
color: white;
}
a, a:visited {
color: white;
}
</style>
</body> </body>
</html> </html>

@ -1,18 +1,16 @@
<form method="POST" action=""> <form method="post" action="">
{% for f in form %} {% for f in form %}
{% if f.name == 'csrf_token' %} {% if f.name == 'csrf_token' %}
{{ f }} {{ f }}
{% else %} {% else %}
<div class="form-group"> {{ f.label }}
{{ f.label }} {{ f }}
{{ f }}
</div>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
<ul> <ul>
{% for field, errors in form.errors.items() %} {%- for field, errors in form.errors.items() %}
<li>{{ form[field].label }}: {{ ', '.join(errors) }}</li> <li>{{ form[field].label }}: {{ ', '.join(errors) }}</li>
{% endfor %} {%- endfor %}
</ul> </ul>
<input type="submit" value="Confirm" class="btn btn-link btn-outline btn-xl"> <input type="submit" value="Submit" class="button-primary">
</form> </form>

@ -1,20 +0,0 @@
<header id="header">
<h1 id="logo"><a href="/">{{ config.SITE_NAME }}</a></h1>
<nav id="nav">
<ul>
<li><a href="{{ url_for('auth.login') }}">Login</a></li>
<li><a href="{{ url_for('auth.register') }}">Register</a></li>
<li><a href="{{ url_for('auth.logout') }}">Logout</a></li>
</ul>
</nav>
</header>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<p>
{% for category, message in messages %}
<p>{{ message }} - {{ category }}</p>
{% endfor %}
</p>
{% endif %}
{% endwith %}

@ -0,0 +1,25 @@
<nav class="navbar">
<div class="container">
<ul class="navbar-list">
<li class="navbar-item"><a class="navbar-link" href="{{ url_for('main.index') }}">Home</a></li>
<li class="navbar-item"><a class="navbar-link" href="{{ url_for('main.about') }}">About</a></li>
{%- if current_user.is_authenticated %}
<li class="navbar-item"><a class="navbar-link" href="{{ url_for('auth.logout') }}">Logout</a></li>
{%- else %}
<li class="navbar-item"><a class="navbar-link" href="{{ url_for('auth.login') }}">Login</a></li>
{%- endif %}
</ul>
</div>
</nav>
<div class="container">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<p>
{% for category, message in messages %}
<p>{{ message }} - {{ category }}</p>
{% endfor %}
</p>
{% endif %}
{% endwith %}
</div>

@ -5,13 +5,14 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<h2>Latest Artworks</h2> <h2>Latest Artworks</h2>
{% for _artwork in feed['artwork'] | batch(4) %} {%- for _artwork in feed['artwork'] | batch(4) %}
{% for artwork in _artwork %} {%- for artwork in _artwork %}
<a href="{{ url_for('artwork.show', id=artwork.id) }}"> <a class="artworkLink" href="{{ url_for('artwork.show', id=artwork.id) }}">
<img src="{{ url_for('main.uploaded_file', filename=artwork.thumbnail) }}" width="150px"> <img src="{{ url_for('main.uploaded_file', filename=artwork.thumbnail) }}" width="150px">
</a> </a>
{% endfor %} {%- endfor %}
{% endfor %} {%- endfor %}
<p><a href="{{ url_for('artwork.list') }}">...view all</a></p>
</div> </div>
<div class="row"> <div class="row">
<h2>Latest Artists</h2> <h2>Latest Artists</h2>

@ -0,0 +1,3 @@
flake8==6.0.0
pyflakes==3.0.1
lorem==0.1.1

@ -5,7 +5,6 @@ certifi==2022.9.24
cffi==1.15.1 cffi==1.15.1
charset-normalizer==2.1.1 charset-normalizer==2.1.1
click==8.1.3 click==8.1.3
flake8==6.0.0
Flask==2.2.2 Flask==2.2.2
Flask-Login==0.6.2 Flask-Login==0.6.2
Flask-Session==0.4.0 Flask-Session==0.4.0
@ -25,7 +24,6 @@ Pillow==9.3.0
pycodestyle==2.10.0 pycodestyle==2.10.0
pycparser==2.21 pycparser==2.21
pycryptodomex==3.16.0 pycryptodomex==3.16.0
pyflakes==3.0.1
PyNaCl==1.5.0 PyNaCl==1.5.0
pyparsing==3.0.9 pyparsing==3.0.9
PySocks==1.7.1 PySocks==1.7.1

Loading…
Cancel
Save