author=self.author.username, name=self.name)
def getMainScreenshotURL(self):
- return self.screenshots[0].url if len(self.screenshots) > 0 else None
+ screenshot = self.screenshots.first()
+ return screenshot.url if screenshot is not None else None
def getDownloadRelease(self):
for rel in self.releases:
--- /dev/null
+
+h1 {
+ margin: 0;
+}
+
+h2, h3 {
+ margin: 5px 0;
+}
+
+a {
+ color: #0be;
+ font-weight: bold;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #0df;
+ text-decoration: underline;
+}
+
+/* Containers */
+
+.box {
+ border-radius: 5px;
+ margin: 15px 0;
+}
+
+.box_grey {
+ padding: 10px;
+ background: #333;
+ border: 1px solid #444;
+}
+
+.ul_boxes {
+ display: block;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.ul_boxes > li {
+ padding: 0;
+ list-style: none;
+}
+
+.box_link {
+ display: block;
+ color: #ddd;
+ text-decoration: none;
+}
+
+.box_link:hover{
+ background: #3a3a3a;
+}
+
+/*
+ buttonset
+*/
+
+.buttonset, .buttonset li {
+ display: block;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.buttonset {
+ margin: 15px 0;
+}
+
+.button, .buttonset li a {
+ text-align: center;
+ display: inline-block;
+ padding: 0.5em 0.7em;
+ background: #333;
+ border: 1px solid #444;
+ color: #ddd;
+ border-radius: 5px;
+ text-decoration: none;
+}
+
+.button:hover, .buttonset li a:hover {
+ background: #444;
+ border: 1px solid #555;
+ text-decoration: none;
+}
+
+.btn_green {
+ background: #363 !important;
+ border: 1px solid #473;
+}
+
+.btn_green:hover {
+ background: #474 !important;
+}
+
+.linedbuttonset a {
+ border: 1px solid #eee;
+ border-radius: 3px;
+ padding: 4px 10px;
+ margin: 0;
+ display: block;
+}
+
+.linedbuttonset {
+ display: block;
+ margin: 0;
+}
+
+.linedbuttonset li {
+ display: inline-block;
+ margin: 10px 10px 0 0;
+}
+
+/* Alerts */
+
+#alerts {
+ list-style: none;
+ position: fixed;
+ bottom: 15px;
+ left: 0;
+ right: 0;
+}
+
+#alerts .alert {
+ margin: 5px 0;
+ vertical-align: middle;
+}
+
+#alerts .close {
+ float: right;
+ color: white;
+}
+
+#alerts .close:hover {
+ color: #fff;
+}
+
+.alert-error {
+ background: #933;
+ border: 1px solid #c44;
+}
+
+.alert-warning {
+ background: #963;
+ border: 1px solid #c96;
+}
+
+.alert-success {
+ background: #161;
+ border: 1px solid #393;
+}
--- /dev/null
+@import "page.scss";
+@import "components.scss";
+@import "packages.scss";
+@import "packagegrid.scss";
--- /dev/null
+.packagegrid {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.packagegrid li {
+ list-style: none;
+ display: inline-block;
+ padding: 0;
+ margin: 8px;
+}
+
+.packagegrid a {
+ display: block;
+ width: 246px;
+ height: 164px;
+ border-radius: 7px;
+ position: relative;
+ overflow: hidden;
+ background-size: cover;
+ background-repeat: no-repeat;
+ background-position: center;
+}
+
+
+.packagegrid a span {
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ padding: 5px;
+ background: rgba(255, 255, 255, 0.3);
+ color: black;
+}
--- /dev/null
+
+.screenshot_list, .screenshot_list li, .screenshot_list li a {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+.screenshot_list li {
+ display: inline-block;
+ margin: 5px;
+ padding: 0;
+}
+
+.screenshot_list li a {
+ display: block;
+}
+
+.screenshot_list img {
+ width: 164px;
+ height: 164px;
+ object-fit: cover;
+}
+
+.box_img {
+ position: relative;
+ background-position: center;
+ background-size: cover;
+ background-image: url("screenshot.png");
+ min-height: 220px;
+ border-radius: 5px;
+ padding: 0;
+}
+
+.box_img > h2 {
+ display: inline-block;
+ position: absolute;
+ bottom: 15px;
+ left: 15px;
+}
+
+.sidebar_container {
+ display: block;
+ position: relative;
+ padding: 0;
+ margin: 0;
+}
+
+.sidebar_container .right, .sidebar_container .left{
+ position: absolute;
+ display: block;
+ top: 10px;
+ margin-top: 0;
+}
+
+.sidebar_container .right {
+ right: 0;
+ width: 280px;
+}
+
+.sidebar_container .left {
+ right: 295px;
+ left: 0;
+}
+
+.sidebar_container .right > *:first-child, .sidebar_container .left > *:first-child {
+ margin-top: 0;
+}
+
+.package-short-large {
+ font-size: 120%;
+}
+
+.pkg_wiz_1, .pkg_wiz_2 {
+ display: none;
+}
--- /dev/null
+html, body {
+ font-family: "Arial", sans-serif;
+ background: #222;
+ color: #ddd;
+ padding: 0;
+ margin: 0;
+}
+
+nav, main, #alerts {
+ width: 90%;
+ max-width: 960px;
+ margin: auto;
+ padding: 0;
+ display: block;
+}
+
+nav {
+ margin: 0 auto 0 auto;
+ list-style: none;
+ background: #333;
+}
+
+nav .navbar-nav {
+ float: left;
+}
+
+nav .navbar-right {
+ float: right;
+}
+
+nav ul {
+ margin: 0 auto 0 auto;
+ padding: 0;
+ list-style: none;
+}
+
+nav li {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ display: inline-block;
+}
+
+nav li a {
+ color: #ddd;
+ margin: 0;
+ padding: 1em 1em;
+ display: block;
+ border-left: 1px solid #444;
+}
+
+nav a:hover {
+ color: #eee;
+ background: #444;
+ text-decoration: none;
+}
+
+header {
+ padding: 20px;
+ background: #113;
+}
+
+
+/* Footer */
+
+footer {
+ width: 80%;
+ max-width: 860px;
+ margin: auto;
+ padding: 50px 0 20px 0;
+}
+
+footer a {
+ color: #666;
+}
+
+.asideright {
+ float: right;
+ margin: 0 0 0 15px;
+ max-width: 300px;
+}
+++ /dev/null
-html, body {
- font-family: "Arial", sans-serif;
- background: #222;
- color: #ddd;
- padding: 0;
- margin: 0;
-}
-
-h1 {
- text-align: center;
-}
-
-.screenshot_list, .screenshot_list li, .screenshot_list li a {
- list-style: none;
- margin: 0;
- padding: 0;
-}
-
-.screenshot_list li {
- display: inline-block;
- margin: 5px;
- padding: 0;
-}
-
-.screenshot_list li a {
- display: block;
-}
-
-.screenshot_list img {
- width: 164px;
- height: 164px;
- object-fit: cover;
-}
-
-
-h2, h3 {
- margin: 5px 0;
-}
-
-a {
- color: #0be;
- font-weight: bold;
- text-decoration: none;
-}
-
-a:hover {
- color: #0df;
- text-decoration: underline;
-}
-
-/* Containers */
-
-.box {
- border-radius: 5px;
- margin: 15px 0;
-}
-
-.box_grey {
- padding: 10px;
- background: #333;
- border: 1px solid #444;
-}
-
-.ul_boxes {
- display: block;
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-.ul_boxes > li {
- padding: 0;
- list-style: none;
-}
-
-.box_link {
- display: block;
- color: #ddd;
- text-decoration: none;
-}
-
-.box_link:hover{
- background: #3a3a3a;
-}
-
-/*
- buttonset
-*/
-
-.buttonset, .buttonset li {
- display: block;
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-.buttonset {
- margin: 15px 0;
-}
-
-.buttonset li a {
- text-align: center;
- color: #ddd;
- text-decoration: none;
-}
-
-.buttonset li a:hover {
- background: #444;
-}
-
-.btn_green {
- background: #363 !important;
- border: 1px solid #473;
-}
-
-.btn_green:hover {
- background: #474 !important;
-}
-
-.linedbuttonset a {
- border: 1px solid #eee;
- border-radius: 3px;
- padding: 4px 10px;
- margin: 0;
- display: block;
-}
-
-.linedbuttonset {
- display: block;
- margin: 0;
-}
-
-.linedbuttonset li {
- display: inline-block;
- margin: 10px 10px 0 0;
-}
-
-/* Alerts */
-
-#alerts {
- list-style: none;
- position: fixed;
- bottom: 15px;
- left: 0;
- right: 0;
-}
-
-#alerts .alert {
- margin: 5px 0;
- vertical-align: middle;
-}
-
-#alerts .close {
- float: right;
- color: white;
-}
-
-#alerts .close:hover {
- color: #fff;
-}
-
-.alert-error {
- background: #933;
- border: 1px solid #c44;
-}
-
-.alert-warning {
- background: #963;
- border: 1px solid #c96;
-}
-
-.alert-success {
- background: #161;
- border: 1px solid #393;
-}
-
-/* Nav */
-
-nav, main, #alerts {
- width: 90%;
- max-width: 960px;
- margin: auto;
- padding: 0;
-}
-
-nav {
- margin: 15px auto 5px auto;
- list-style: none;
- background: #333;
- border-radius: 5px;
- border: 1px solid #444;
-}
-
-nav .navbar-nav {
- float: left;
-}
-
-nav .navbar-right {
- float: right;
-}
-
-nav ul {
- margin: 0 auto 0 auto;
- padding: 0;
- list-style: none;
-}
-
-nav li {
- margin: 0;
- padding: 0;
- list-style: none;
- display: inline-block;
-}
-
-nav li a {
- color: #ddd;
- margin: 0;
- padding: 10px 20px;
- display: block;
- border-left: 1px solid #444;
-}
-
-nav a:hover {
- color: #eee;
- background: #444;
- text-decoration: none;
-}
-
-
-/* Footer */
-
-footer {
- width: 80%;
- max-width: 860px;
- margin: auto;
- padding: 50px 0 20px 0;
-}
-
-footer a {
- color: #666;
-}
-
-.asideright {
- float: right;
- margin: 0 0 0 15px;
- max-width: 300px;
-}
-
-
-/* Mod */
-
-.box_img {
- position: relative;
- background-position: center;
- background-size: cover;
- background-image: url("screenshot.png");
- min-height: 220px;
- border-radius: 5px;
- padding: 0;
-}
-
-.box_img > h2 {
- display: inline-block;
- position: absolute;
- bottom: 15px;
- left: 15px;
-}
-
-.sidebar_container {
- display: block;
- position: relative;
- padding: 0;
- margin: 0;
-}
-
-.sidebar_container .right, .sidebar_container .left{
- position: absolute;
- display: block;
- top: 10px;
- margin-top: 0;
-}
-
-.sidebar_container .right {
- right: 0;
- width: 280px;
-}
-
-.sidebar_container .left {
- right: 295px;
- left: 0;
-}
-
-.sidebar_container .right > *:first-child, .sidebar_container .left > *:first-child {
- margin-top: 0;
-}
-
-.package-short-large {
- font-size: 120%;
-}
-
-.pkg_wiz_1, .pkg_wiz_2 {
- display: none;
-}
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}title{% endblock %} - {{ config.USER_APP_NAME }}</title>
- <link rel="stylesheet" type="text/css" href="/static/style.css">
+ <link rel="stylesheet" type="text/css" href="/static/main.css">
</head>
<body>
{% endblock %}
{% block content %}
+ <header>
+ <h1>Content DB</h1>
- <form method="get" action="/packages/">
- <input type="text" name="q" value="{{ query or ''}}" />
- <input type="submit" value="Search" />
- </form>
+ <p>Minetest's official content repository</p>
- <div class="box box_grey">
- <h2>{{ self.title() }}</h2>
+ <form method="get" action="/packages/">
+ <input type="text" name="q" value="{{ query or ''}}" />
+ <input type="submit" value="Search" />
+ </form>
+ <p>
{% if current_user.is_authenticated %}
- <p>
- Hello user!
- </p>
+ <a href="{{ url_for('user_profile_page', username=current_user.username) }}"
+ class="button button-primary">My Packages</a>
{% else %}
- <p>
- Please login!
- </p>
+ <a href="{{ url_for('user.login') }}" class="button button-primary">Join</a>
{% endif %}
- </div>
+ </p>
+ </header>
- <div class="2box">
- <div class="box box_grey">
- <h2>Top Mods</h2>
- </div>
- <div class="box box_grey">
- <h2>Statistics</h2>
- <ul>
- <li>Total mods: 543</li>
- <li>Missing mods: 1020</li>
- <li>Downloads/day: 200</li>
- </ul>
- </div>
- </div>
+ <ul class="packagegrid">
+ {% for p in packages %}
+ <li><a href="{{ p.getDetailsURL() }}"
+ style="background-image: url({{ p.getMainScreenshotURL() or '/static/screenshot.png' }});">
+ <span>{{ p.title }} by {{ p.author.display_name }}</span>
+ </a></li>
+ {% else %}
+ <li><i>No packages available</i></ul>
+ {% endfor %}
+ </ul>
{% endblock %}
@app.route("/")
@menu.register_menu(app, ".", "Home")
def home_page():
- return render_template("index.html")
+ packages = Package.query.filter_by(approved=True).all()
+ return render_template("index.html", packages=packages)
-from . import users, githublogin, packages
+from . import users, githublogin, packages, sass
--- /dev/null
+# -*- coding: utf-8 -*-
+"""
+A small Flask extension that makes it easy to use Sass (SCSS) with your
+Flask application.
+
+Code unabashedly adapted from https://github.com/weapp/flask-coffee2js
+
+:copyright: (c) 2012 by Ivan Miric.
+:license: MIT, see LICENSE for more details.
+"""
+
+import os
+import os.path
+import codecs
+from flask import *
+from scss import Scss
+
+from app import app
+
+def _convert(dir, src, dst):
+ original_wd = os.getcwd()
+ os.chdir(dir)
+
+ css = Scss()
+ source = codecs.open(src, 'r', encoding='utf-8').read()
+ output = css.compile(source)
+
+ os.chdir(original_wd)
+
+ outfile = codecs.open(dst, 'w', encoding='utf-8')
+ outfile.write(output)
+ outfile.close()
+
+def _getDirPath(originalPath, create=False):
+ path = originalPath
+
+ if not os.path.isdir(path):
+ path = os.path.join(app.root_path, path)
+
+ if not os.path.isdir(path):
+ if create:
+ os.mkdir(path)
+ else:
+ raise IOError("Unable to find " + originalPath)
+
+ return path
+
+def sass(app, inputDir='scss', outputPath='static', force=False, cacheDir=None):
+ static_url_path = app.static_url_path
+ inputDir = _getDirPath(inputDir)
+ cacheDir = _getDirPath(cacheDir or outputPath, True)
+
+ def _sass(filepath):
+ sassfile = "%s/%s.scss" % (inputDir, filepath)
+ cacheFile = "%s/%s.css" % (cacheDir, filepath)
+
+ # Source file exists, and needs regenerating
+ if os.path.isfile(sassfile) and (force or not os.path.isfile(cacheFile) or \
+ os.path.getmtime(sassfile) > os.path.getmtime(cacheFile)):
+ _convert(inputDir, sassfile, cacheFile)
+ app.logger.debug('Compiled %s into %s' % (sassfile, cacheFile))
+
+ return send_from_directory(cacheDir, filepath + ".css")
+
+ app.add_url_rule("/%s/<path:filepath>.css" % (outputPath), 'sass', _sass)
+
+sass(app)
Flask-Menu>=0.7.0
Flask-Markdown>=0.3
GitHub-Flask>=3.2.0
+pyScss==1.3.4