appstore: draft app page with markdown description, screenshot, buttons for demo and vote

This commit is contained in:
Alexandre Aubin 2023-08-22 22:54:49 +02:00
parent c6cfcfdc78
commit 6915740484
6 changed files with 131 additions and 11 deletions

View file

@ -1,3 +1,4 @@
import markdown
import time
import re
import toml
@ -13,6 +14,7 @@ from slugify import slugify
from flask import Flask, send_from_directory, render_template, session, redirect, request
from github import Github, InputGitAuthor
locale = "en"
app = Flask(__name__, static_url_path='/assets', static_folder="assets")
catalog = json.load(open("apps.json"))
catalog['categories'] = {c['id']:c for c in catalog['categories']}
@ -122,8 +124,48 @@ def browse_catalog(category_filter=None):
@app.route('/app/<app_id>')
def app_info(app_id):
infos = catalog["apps"].get(app_id)
if not infos:
app_folder = os.path.join(config["APPS_CACHE"], app_id)
if not infos or not os.path.exists(app_folder):
return f"App {app_id} not found", 404
if os.path.exists(os.path.join(app_folder, "doc", f"DESCRIPTION_{locale}.md")):
description_path = os.path.join(app_folder, "doc", f"DESCRIPTION_{locale}.md")
elif os.path.exists(os.path.join(app_folder, "doc", "DESCRIPTION.md")):
description_path = os.path.join(app_folder, "doc", "DESCRIPTION.md")
else:
description_path = None
if description_path:
with open(description_path) as f:
infos["full_description_html"] = markdown.markdown(f.read())
else:
infos["full_description_html"] = infos['manifest']['description'][locale]
if os.path.exists(os.path.join(app_folder, "doc", f"PRE_INSTALL_{locale}.md")):
pre_install_path = os.path.join(app_folder, "doc", f"PRE_INSTALL_{locale}.md")
elif os.path.exists(os.path.join(app_folder, "doc", "PRE_INSTALL.md")):
pre_install_path = os.path.join(app_folder, "doc", "PRE_INSTALL.md")
else:
pre_install_path = None
if pre_install_path:
with open(pre_install_path) as f:
infos["pre_install_html"] = markdown.markdown(f.read())
infos["screenshot"] = None
screenshots_folder = os.path.join(app_folder, "doc", "screenshots")
if os.path.exists(screenshots_folder):
with os.scandir(screenshots_folder) as it:
for entry in it:
ext = os.path.splitext(entry.name)[1].replace(".", "").lower()
if entry.is_file() and ext in ("png", "jpg", "jpeg", "webp", "gif"):
with open(entry.path, "rb") as img_file:
data = base64.b64encode(img_file.read()).decode("utf-8")
infos[
"screenshot"
] = f"data:image/{ext};charset=utf-8;base64,{data}"
break
return render_template("app.html", user=session.get('user', {}), app_id=app_id, infos=infos)

View file

@ -2,3 +2,4 @@ Flask==2.3.2
python-slugify
PyGithub
toml
markdown

View file

@ -1,9 +1,55 @@
{% extends "base.html" %}
{% block main %}
<div class="max-w-screen-lg mx-auto pt-5">
<div class="max-w-screen-md mx-auto pt-5">
<h2>{{ app_id }}</h2>
<span class="flex mb-3">
<img {% if infos['logo_hash'] %}
src="https://app.yunohost.org/default/v3/logos/{{ infos['logo_hash'] }}.png"
{% else %}
src="{{ url_for('static', filename='app_logo_placeholder.png') }}"
{% endif %}
loading="lazy"
class="h-12 w-12 rounded-lg object-cover shadow-sm mt-1"
/>
<h2 class="grow pl-2 pt-3 text-3xl font-bold text-gray-900">{{ infos["manifest"]["name"] }}</h2>
<div class="mt-2">
<a
href="#"
class="mr-3 inline-block group btn border text-violet-600 border-violet-500 hover:bg-violet-500 hover:text-white"
>
123 <i class="fa fa-star-o inline-block group-hover:hidden" aria-hidden="true"></i>
<i class="fa fa-star hidden group-hover:inline-block" aria-hidden="true"></i>
</a>
{% if infos["manifest"]["upstream"]["demo"] %}
<a
class="btn btn-success inline-block"
href="{{ infos["manifest"]["upstream"]["demo"] }}"
>
<i class="fa fa-external-link fa-fw" aria-hidden="true"></i>
Try the demo
</a>
{% endif %}
</div>
</span>
<p>{{ infos }}</p>
<p class="text-sm text-slate-500">Current version: {{ infos["manifest"]["version"] }}</p>
{% if infos["potential_alternative_to"] %}
<p class="text-sm text-slate-500">Potential alternative to: {{ infos["potential_alternative_to"]|join(', ') }}</p>
{% endif %}
<div class="from-markdown">{{ infos["full_description_html"]|safe }}</div>
{% if infos["screenshot"] %}
<img src="{{ infos["screenshot"] }}" />
{% endif %}
<p>{{ infos["category"] }}</p>
<p>{{ infos["level"] }}</p>
<p>Antifeatures: {{ infos["anti_features"] }}</p>
<p>{{ infos["manifest"]["integration"] }}</p>
<p>{{ infos["manifest"]["upstream"] }}</p>
<div class="from-markdown">{{ infos["pre_install_html"] | safe }}</div>
</div>
{% endblock %}

View file

@ -7,6 +7,38 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="{{ url_for('static', filename='tailwindcss.js') }}"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='fork-awesome.min.css') }}" rel="preload">
<style type="text/tailwindcss">
@layer utilities {
.btn {
@apply text-sm font-medium rounded-md px-4 py-2.5 transition;
}
.btn-sm {
@apply text-xs font-medium rounded-md px-2 py-2 transition;
}
.btn-success {
@apply text-white bg-green-500 hover:bg-green-700;
}
.btn-primary {
@apply text-white bg-blue-500 hover:bg-blue-700;
}
.btn-primary-outline {
@apply border text-blue-600 border-blue-500 hover:text-blue-400;
}
.from-markdown {
@apply my-4;
}
.from-markdown p {
@apply mb-2;
}
.from-markdown h3 {
@apply text-xl mb-1 font-semibold;
}
.from-markdown ul {
padding: revert;
list-style: disc;
}
}
</style>
</head>
<body>
@ -39,7 +71,7 @@
<div class="flex items-center gap-4">
<div class="sm:flex sm:gap-4">
<a
class="rounded-md border text-blue-600 border-blue-500 px-5 py-2.5 text-sm font-medium hover:text-blue-400 hidden md:block"
class="btn btn-primary-outline hidden md:inline-block"
href="https://yunohost.org/docs/"
>
<i class="fa fa-external-link fa-fw" aria-hidden="true"></i>
@ -47,7 +79,7 @@
</a>
{% if not user %}
<a
class="rounded-md bg-blue-500 px-5 py-2.5 text-sm font-medium text-white transition hover:bg-blue-700 hidden md:block"
class="btn btn-primary hidden md:inline-block"
href="{{ url_for('login_using_discourse') }}"
>
Login using YunoHost's forum
@ -63,7 +95,7 @@
src="{{ user['avatar_url'] }}"
class="h-10 w-10 rounded-full object-cover"
/>
<p class="ms-2 hidden text-left text-xs sm:block">
<p class="ms-2 hidden text-left text-xs sm:inline-block">
<strong class="block font-medium">{{ user['username'] }}</strong>
</p>
<i class="fa fa-caret-down fa-fw" aria-hidden="true"></i>

View file

@ -25,7 +25,7 @@
<a
class="inline-block rounded-md border text-blue-600 border-blue-500 px-4 pt-3 text-sm font-medium hover:bg-blue-500 hover:text-white"
class="btn btn-primary-outline"
href="{{ url_for('add_to_wishlist') }}"
>
<i class="fa fa-plus fa-fw" aria-hidden="true"></i>
@ -83,12 +83,11 @@
<td class="text-center max-w-[5em]">
<a
href="#"
class="inline-block group rounded-md border text-violet-600 border-violet-500 px-2 py-2 text-xs font-medium hover:bg-violet-500 hover:text-white"
class="inline-block group btn-sm border text-violet-600 border-violet-500 hover:bg-violet-500 hover:text-white"
>
123 <i class="fa fa-star-o inline-block group-hover:hidden" aria-hidden="true"></i>
<i class="fa fa-star hidden group-hover:inline-block" aria-hidden="true"></i>
</a>
</a>
</td>
</tr>
{% endfor %}

View file

@ -66,7 +66,7 @@
<button
type="submit"
class="mx-auto block rounded-md border text-white bg-blue-500 px-4 mt-5 py-2 font-medium {% if user %}hover:bg-blue-700{% endif %}"
class="block mx-auto btn btn-primary mt-5 {% if user %}hover:bg-blue-700{% endif %}"
{% if not user %}disabled{% endif %}
>
Submit