This commit is contained in:
Stefan Friese 2022-09-06 23:45:26 +02:00
parent 30e56fcff5
commit a5518e277c
5 changed files with 116 additions and 220 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
__pycache__/
templates/content/
bkp.*
poetry.lock
build

64
helpers.py Normal file
View File

@ -0,0 +1,64 @@
import os
def make_tree(path="templates/content"):
if '/' in path:
tree = dict(name=path, children=[], type="directory")
else:
pass
try: lst = os.listdir(path)
except OSError:
pass #ignore errors
else:
lst.sort()
for name in lst:
fn = os.path.join(path, name)
if os.path.isdir(fn) and not fn.endswith(".git"):
tree['children'].append(make_tree(fn))
else:
if fn.endswith('.md') and not name == "README.md":
tree['children'].append(dict(name=fn))
return tree
def cut_path_tree(tree, subdir, file_ending):
for key, val in tree.items():
if isinstance(val, list):
for item in val:
item["name"] = item["name"][len(subdir):]
if item["name"].endswith(file_ending):
item["name"] = item["name"][:-len(file_ending)]
if isinstance(item, dict):
cut_path_tree(item, subdir, file_ending)
return tree
def cut_filetype_tree(tree, filetype):
for key, val in tree.items():
if isinstance(val, list):
for item in val:
if item["name"].endswith(filetype):
item["name"] = item["name"][:-len(filetype)]
if isinstance(item, dict):
cut_filetype_tree(item, filetype)
return tree
def list_files(path):
doc_files = []
for root, dirs, files in os.walk(path):
for file in files:
if file.endswith(".md") and not ".git" in root:
doc_files.append(os.path.join(root,file))
return doc_files
def build_index(path, file_ending):
searchable = dict(index=[])
file_list = list_files(path)
for item in file_list:
if item.endswith(file_ending):
with open(item, 'r') as _f:
data = _f.readlines()
data[0] = data[0].strip('# \n')
#searchable[data[0]] = [''.join(data), item[len(path):-len(file_ending)]]
searchable["index"].append(dict(uri=item[len(path):-len(file_ending)] + '.html', title=data[0],tags=[],content=''.join(data), description=""))
#searchable[str(uuid.uuid1())] = (dict(href=item[len(path):-len(file_ending)], title=data[0],tags=[],content=''.join(data)))
if isinstance(item, dict):
build_index(item)
return searchable

21
pyproject.toml Normal file
View File

@ -0,0 +1,21 @@
[tool.poetry]
name = "husk"
version = "0.1.0"
description = "Generate a website from a markdown repository"
authors = ["Stefan Friese <mail@stefan.works>"]
license = "GPLv2"
[tool.poetry.dependencies]
python = "^3.10"
Flask = "^2.0.2"
Frozen-Flask = "^0.18"
Markdown = "^3.4.1"
Flask-Markdown = "^0.3"
Pygments = "^2.12.0"
python-markdown-math = "*"
[tool.poetry.dev-dependencies]
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

View File

@ -2,8 +2,6 @@
import os
import uuid
#from datetime import datetime
#import pytz
from flask import Flask, url_for, render_template, send_from_directory, jsonify, make_response
from flaskext.markdown import Markdown
import markdown
@ -12,97 +10,15 @@ import markdown.extensions.codehilite
import markdown.extensions.toc
from markdown.extensions.toc import TocExtension
from pygments.formatters import HtmlFormatter
from helpers import make_tree, cut_path_tree, cut_filetype_tree, list_files, build_index
app = Flask(__name__)
Markdown(app)
def make_tree(path="templates/content"):
if '/' in path:
tree = dict(name=path, children=[], type="directory")
else:
pass
try: lst = os.listdir(path)
except OSError:
pass #ignore errors
else:
lst.sort()
for name in lst:
fn = os.path.join(path, name)
if os.path.isdir(fn) and not fn.endswith(".git"):
tree['children'].append(make_tree(fn))
else:
if fn.endswith('.md') and not name == "README.md":
tree['children'].append(dict(name=fn))
return tree
def cut_path_tree(tree, subdir, file_ending):
for key, val in tree.items():
if isinstance(val, list):
for item in val:
item["name"] = item["name"][len(subdir):]
if item["name"].endswith(file_ending):
item["name"] = item["name"][:-len(file_ending)]
if isinstance(item, dict):
cut_path_tree(item, subdir, file_ending)
return tree
def cut_filetype_tree(tree, filetype):
for key, val in tree.items():
if isinstance(val, list):
for item in val:
if item["name"].endswith(filetype):
item["name"] = item["name"][:-len(filetype)]
if isinstance(item, dict):
cut_filetype_tree(item, filetype)
return tree
def list_files(path):
doc_files = []
for root, dirs, files in os.walk(path):
for file in files:
if file.endswith(".md") and not ".git" in root:
doc_files.append(os.path.join(root,file))
return doc_files
#
#def dir_structure():
# for root, dirs, files in os.walk("./templates/content"):
# if len(files) != 0:
# print(root.split('/')[3:], [file[:-3] for file in files if file.endswith('.md')])
#
#def test_def():
# for i,line in enumerate(l):
# if len(line[0]) > 0:
# dic[str(line[0][-1])] = line[-1]
# result = {}
# curr = result
# for p in line[0]:
# curr = curr.setdefault(p, {})
#def other_test_def():
# for root, dirs, files in os.walk("templates/content"):
# #print(root[18:].split('/')[0])
## print(root, files)
# key = root[18:].split('/')[0]
# d[key] = [file[:-3] for file in files]
def build_index(path, file_ending):
searchable = dict(index=[])
file_list = list_files(path)
for item in file_list:
if item.endswith(file_ending):
with open(item, 'r') as _f:
data = _f.readlines()
data[0] = data[0].strip('# \n')
#searchable[data[0]] = [''.join(data), item[len(path):-len(file_ending)]]
searchable["index"].append(dict(uri=item[len(path):-len(file_ending)] + '.html', title=data[0],tags=[],content=''.join(data), description=""))
#searchable[str(uuid.uuid1())] = (dict(href=item[len(path):-len(file_ending)], title=data[0],tags=[],content=''.join(data)))
if isinstance(item, dict):
build_index(item)
return searchable
@app.route('/index.json')
def index():
searchable = build_index("templates/content", ".md")
#searchable = dict(index=[ dict(title="Smp_000020", uri="/geneexp/sm/Smp_000020.1/",content="bifunctional protein NCOAT", tags=[], description=""), dict(title="Smp_000030",uri="/geneexp/sm/Smp_000030.1/",content="26s proteasome regulatory particle subunit", tags=[], description="")])
response = make_response(searchable)
response.headers["Content-Type"] = "application/json"
#response.headers["Content-Encoding"] = "gzip"
@ -131,41 +47,9 @@ def content(path="README"):
response.headers["Content-Type"]: "text/html; charset=utf-8"
return response
#@app.route('/blog/<blog_item>/index.html')
#def blog(blog_item, _date=meta_data):
# return render_template(f"blog/{blog_item}/index.html", _date=meta_data[blog_item], )
#@app.route("/about.html")
#def about():
# return render_template("about.html")
#
#@app.route("/contact.html")
#def contact():
# return render_template("contact.html")
@app.route('/favicon.ico')
def favicon():
return send_from_directory(os.path.join(app.root_path, 'static'), 'favicon.ico')
#@app.errorhandler(404)
#def page_not_found(_error):
# return render_template("/status_code/404.html"), 404
#
#@app.errorhandler(400)
#def bad_request(_error):
# return render_template("/status_code/400.html"), 400
#
#@app.errorhandler(500)
#def internal_server_error(_error):
# return render_template("/status_code/500.html"), 500
with app.test_request_context():
#print(url_for("content"))
#print(url_for("about"))
# print(url_for("contact"))
#print(url_for("rss"))
#print(url_for("static", filename="stylesheet.css"))
#print(meta_data)
print(url_for("content", md_file="enumeration/windows/bloodhound"))
print(url_for("content", md_file="README"))

View File

@ -4,11 +4,10 @@
<head>
{% block head %}
<script src="https://cdn.jsdelivr.net/npm/fuse.js/dist/fuse.js"></script>
<!-- mathjax -->
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/auto-complete.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/lunr.min.js')}}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/search.js')}}"></script>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/auto-complete.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/lunr.min.js')}}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/search.js')}}"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='stylesheet.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='auto-complete.css') }}">
<br>
@ -19,7 +18,7 @@
<body>
<!-- topmenu -->
<div class="menu">
<a href="{{ url_for('content') }}" style="text-decoration:none">In the Open</a>
<a href="{{ url_for('content') }}" style="text-decoration:none">Husk</a>
</div>
<div class="search-container">
<label for="search-by"><i class="fas fa-search"></i></label>
@ -65,109 +64,34 @@
</div>
<script>
function linkClick(obj) {
function linkClick(obj) {
if (obj.open) {
console.log('open');
//console.log('open');
if (sessionStorage.getItem(obj.id) && !(sessionStorage.getItem(obj.id) === "open")) {
sessionStorage.removeItem(obj.id);
}
sessionStorage.setItem(obj.id,"open");
console.log(obj.id);
sessionStorage.setItem(obj.id,"open");
console.log(obj.id);
} else {
console.log('closed');
sessionStorage.removeItem(obj.id);
}
// if (obj.open) {
// console.log('open');
// if (sessionStorage.getItem("opened") && !(sessionStorage.getItem("opened") === obj.id)) {
// sessionStorage.removeItem("opened");
// }
// sessionStorage.setItem("opened", obj.id);
// console.log(obj);
//console.log('closed');
sessionStorage.removeItem(obj.id);
}
}
// } else {
// console.log('closed');
// sessionStorage.removeItem("opened");
//
// }
}
//if ( sessionStorage.getItem("opened")) {
// var item = sessionStorage.getItem("opened")
// document.getElementById(item)['open'] = 'open';
//}
let _keys = Object.keys(sessionStorage);
if (_keys) {
for ( let i = 0; i < _keys.length; i++ ) {
document.getElementById(_keys[i])['open'] = 'open';
}
}
// const detailsElement = document.querySelector('.details-sidebar');
// detailsElement.addEventListener('toggle', event => {
// if (event.target.open) {
// console.log('open');
// if (sessionStorage.getItem("opened") && !(sessionStorage.getItem("opened") === detailsElement.id)) {
// sessionStorage.removeItem("opened");
// }
// sessionStorage.setItem("opened", detailsElement.id);
// console.log(detailsElement);
//
// } else {
// console.log('closed');
// sessionStorage.removeItem("opened");
//
// }
// });
//
// async function fetchIndexJSON() {
// const response = await fetch('/index.json');
// const index = await response.json();
// return index;
// }
// // Extract the `q` query parameter
//var queryStringRegex = /[\?&]q=([^&]+)/g;
//var matches = queryStringRegex.exec(window.location.search);
//if(matches && matches[1]) {
// var value = decodeURIComponent(matches[1].replace(/\+/g, '%20'));
//
//
// // fetchIndexJSON()
// // .then(index => { console.log(index['index']);});
// // Load the posts to search
// fetch('/index').then(function(posts) {
// // Remember to include Fuse.js before this script.
//
// var fuse = new Fuse(posts, {
// keys: ['title', 'tags', 'content'] // What we're searching
// });
//
// // Run the search
// var results = fuse.search(value);
// //console.log(results);
//
// // Generate markup for the posts, implement SearchResults however you want.
// // var $results = SearchResults(results);
//
// // Add the element to the empty <div> from before.
//// $('#searchResults').append($results);
// });
//}
let _keys = Object.keys(sessionStorage);
if (_keys) {
for ( let i = 0; i < _keys.length; i++ ) {
document.getElementById(_keys[i])['open'] = 'open';
}
}
</script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js"></script>
<script src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"></script>
</script>
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"></script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
config: ["MMLorHTML.js"],
jax: ["input/TeX", "output/HTML-CSS", "output/NativeMML"],
extensions: ["MathMenu.js", "MathZoom.js"]
});
</script>
MathJax.Hub.Config({
config: ["MMLorHTML.js"],
jax: ["input/TeX", "output/HTML-CSS", "output/NativeMML"],
extensions: ["MathMenu.js", "MathZoom.js"]
});
</script>
</body>
</html>