Add inline_svg

This commit is contained in:
Yusur 2021-10-17 10:20:47 +02:00
parent baed59ea39
commit 8b5e2ed41b
18 changed files with 56 additions and 21 deletions

View file

@ -2,6 +2,7 @@
## 0.9-dev
* Website redesign: added some material icons, implemented via a `inline_svg` function, injected by default in templates and defined in `utils.py`.
* Added positive feedback mechanism: now you can +1 a message. So, `score_message_add` and `score_message_remove` API endpoints were added, and `MessageUpvote` table was created.
* Added notifications support for API.
* Added `create_account` endpoint to API. This endpoint does not require an access token.

View file

@ -30,6 +30,8 @@ __version__ = '0.9-dev'
if sys.version_info[0] < 3:
raise RuntimeError('Python 3 required')
os.chdir(os.path.dirname(os.path.dirname(__file__)))
app = Flask(__name__)
app.config.from_pyfile('../config.py')
@ -60,7 +62,11 @@ def after_request(response):
@app.context_processor
def _inject_variables():
return {'site_name': app.config['SITE_NAME'], 'locations': locations}
return {
'site_name': app.config['SITE_NAME'],
'locations': locations,
'inline_svg': inline_svg
}
@login_manager.user_loader
def _inject_user(userid):

View file

@ -4,7 +4,7 @@ Filter functions used in the website templates.
from flask import Markup
import html, datetime, re, time
from .utils import tokenize
from .utils import tokenize, inline_svg as _inline_svg
from . import app
@app.template_filter()
@ -64,3 +64,4 @@ def is_following(from_user, to_user):
def locationdata(key):
if key > 0:
return locations[str(key)]

View file

@ -17,7 +17,7 @@ import os
# here should go `from .utils import get_current_user`, but it will cause
# import errors. It's instead imported at function level.
database = SqliteDatabase(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'coriplus.sqlite'))
database = SqliteDatabase('coriplus.sqlite')
class BaseModel(Model):
class Meta:
@ -51,8 +51,7 @@ class User(BaseModel):
return False
@property
def is_authenticated(self):
from .utils import get_current_user
return self == get_current_user()
return True
# it often makes sense to put convenience methods on model instances, for
# example, "give me all the users this user is following":

View file

@ -1,9 +1,16 @@
body,button,input,select,textarea{font-family:'Segoe UI',Arial,Helvetica,sans-serif}
body,button,input,select,textarea{font-family:Roboto,'Segoe UI',Arial,Helvetica,sans-serif}
body{margin:0}
.header{padding:12px;color:white;background-color:#ff3018}
a{text-decoration:none}
a:hover{text-decoration:underline}
@media (max-width:640px){
.mobile-collapse{display:none}
}
.header{padding:12px;color:white;background-color:#ff3018;box-shadow:0 0 3px 3px #ccc}
.content{padding:12px}
.header a{color:white}
.header a svg{fill:white}
.content a{color:#3399ff}
.content a svg{fill:#3399ff}
.content a.plus{color:#ff3018}
.metanav{float:right}
.header h1{margin:0;display:inline-block}
@ -14,7 +21,9 @@ body{margin:0}
}
.weak{opacity:.5}
.field_desc{display:block}
.message-visual img{max-width:100%;max-height:8em}
ul.timeline{padding:0;margin:auto;max-width:960px}
ul.timeline > li{list-style:none;border-bottom:#808080 1px solid}
.message-visual img{max-width:100%;margin:auto}
.message-options-showhide::before{content:'\2026'}
.message-options{display:none}
.create_text{width:100%;height:8em}

View file

@ -12,18 +12,18 @@
<h1><a href="{{ url_for('website.homepage') }}">{{ site_name }}</a></h1>
<div class="metanav">
{% if current_user.is_anonymous %}
<a href="{{ url_for('website.login', next=request.full_path) }}">log in</a>
<a href="{{ url_for('website.register', next=request.full_path) }}">register</a>
<a href="{{ url_for('website.login', next=request.full_path) }}">{{ inline_svg('exit_to_app') }} log in</a>
<a href="{{ url_for('website.register', next=request.full_path) }}">{{ inline_svg('person_add') }} register</a>
{% else %}
<a href="{{ url_for('website.user_detail', username=current_user.username) }}">{{ current_user.username }}</a>
<a href="{{ url_for('website.user_detail', username=current_user.username) }}">{{ inline_svg('person') }} {{ current_user.username }}</a>
{% set notification_count = current_user.unseen_notification_count() %}
{% if notification_count > 0 %}
<a href="{{ url_for('website.notifications') }}">(<strong>{{ notification_count }}</strong>)</a>
{% endif %}
-
<a href="{{ url_for('website.public_timeline') }}">explore</a>
<a href="{{ url_for('website.create') }}">create</a>
<a href="{{ url_for('website.logout') }}">log out</a>
<a href="{{ url_for('website.public_timeline') }}">{{ inline_svg('explore') }} explore</a>
<a href="{{ url_for('website.create') }}">{{ inline_svg('edit') }} create</a>
<a href="{{ url_for('website.logout') }}">{{ inline_svg('exit_to_app') }} log out</a>
{% endif %}
</div>
</div>
@ -36,7 +36,8 @@
<div class="footer">
<p class="copyright">&copy; 2019 Sakuragasaki46.
<a href="/about/">About</a> - <a href="/terms/">Terms</a> -
<a href="/privacy/">Privacy</a></p>
<a href="/privacy/">Privacy</a> -
<a href="https://github.com/sakuragasaki46/coriplus">GitHub</a></p>
</div>
<script src="/static/lib.js"></script>
</body>

View file

@ -1,7 +1,7 @@
{% extends "base.html" %}
{% block body %}
<h2>Explore</h2>
<ul>
<ul class="timeline">
{% for message in message_list %}
<li id="{{ message.id }}">{% include "includes/message.html" %}</li>
{% endfor %}

View file

@ -1,7 +1,7 @@
{% extends "base.html" %}
{% block body %}
<h2>Your Timeline</h2>
<ul>
<ul class="timeline">
{% for message in message_list %}
<li id="{{ message.id }}">{% include "includes/message.html" %}</li>
{% endfor %}

View file

@ -30,6 +30,6 @@
<a href="{{ url_for('website.user_following', username=user.username) }}"><strong>{{ user.following()|count }}</strong></a> following
</p>
{% if user == current_user %}
<p><a href="/edit_profile/">Edit profile</a></p>
<p><a href="/edit_profile/">{{ inline_svg('edit', 18) }} Edit profile</a></p>
{% endif %}
</div>

View file

@ -18,7 +18,7 @@
<a href="/create/">Create a message</a>
{% endif %}
{% endif %}
<ul>
<ul class="timeline">
{% for message in message_list %}
<li id="{{ message.id }}">{% include "includes/message.html" %}</li>
{% endfor %}

View file

@ -5,7 +5,7 @@ A list of utilities used across modules.
import datetime, re, base64, hashlib, string, sys, json
from .models import User, Message, Notification, MSGPRV_PUBLIC, MSGPRV_UNLISTED, \
MSGPRV_FRIENDS, MSGPRV_ONLYME
from flask import abort, render_template, request, session
from flask import Markup, abort, render_template, request, session
_forbidden_extensions = 'com net org txt'.split()
_username_characters = frozenset(string.ascii_letters + string.digits + '_')
@ -82,7 +82,7 @@ class Visibility(object):
def get_locations():
data = {}
with open('locations.txt') as f:
with open('locations.txt', encoding='utf-8') as f:
for line in f:
line = line.rstrip()
if line.startswith('#'):
@ -215,3 +215,14 @@ def create_mentions(cur_user, text, privacy):
push_notification('mention', mention_user, user=user.id)
except User.DoesNotExist:
pass
# New in 0.9
def inline_svg(name, width=None):
try:
with open('icons/' + name + '-24px.svg') as f:
data = f.read()
if isinstance(width, int):
data = re.sub(r'( (?:height|width)=")\d+(")', lambda x:x.group(1) + str(width) + x.group(2), data)
return Markup(data)
except OSError:
return ''

1
icons/edit-24px.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/><path d="M0 0h24v24H0z" fill="none"/></svg>

After

Width:  |  Height:  |  Size: 287 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M10.09 15.59L11.5 17l5-5-5-5-1.41 1.41L12.67 11H3v2h9.67l-2.58 2.59zM19 3H5c-1.11 0-2 .9-2 2v4h2V5h14v14H5v-4H3v4c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/></svg>

After

Width:  |  Height:  |  Size: 302 B

1
icons/explore-24px.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M12 10.9c-.61 0-1.1.49-1.1 1.1s.49 1.1 1.1 1.1c.61 0 1.1-.49 1.1-1.1s-.49-1.1-1.1-1.1zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm2.19 12.19L6 18l3.81-8.19L18 6l-3.81 8.19z"/><path d="M0 0h24v24H0z" fill="none"/></svg>

After

Width:  |  Height:  |  Size: 333 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"/></svg>

After

Width:  |  Height:  |  Size: 261 B

1
icons/person-24px.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/><path d="M0 0h24v24H0z" fill="none"/></svg>

After

Width:  |  Height:  |  Size: 247 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M15 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm-9-2V7H4v3H1v2h3v3h2v-3h3v-2H6zm9 4c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg>

After

Width:  |  Height:  |  Size: 279 B

1
icons/shuffle-24px.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M10.59 9.17L5.41 4 4 5.41l5.17 5.17 1.42-1.41zM14.5 4l2.04 2.04L4 18.59 5.41 20 17.96 7.46 20 9.5V4h-5.5zm.33 9.41l-1.41 1.41 3.13 3.13L14.5 20H20v-5.5l-2.04 2.04-3.13-3.13z"/></svg>

After

Width:  |  Height:  |  Size: 311 B