So, I realized that I was able to solve my problem.
I managed to get this very functional result: 
Please note that my template is only good for files with the .html extension, although it can be easily extended to support other file extensions.
Here is my finalized templates\template.html file:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Docs Demo</title> <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}"> </head> <body> <div id="container"> <div class="left_frame"> <h1>{{ tree.name }}</h1> <ul> {%- for item in tree.children recursive %} {% if '.html' in item.name %} <li><a href="docs/{{ item.name }}" target="iframe1"> {{ item.name.split('/')[-1:][0] }} {%- if item.children -%} <ul>{{ loop(item.children) }}</ul> {%- endif %}</a></li> {% else %} <li>{{ item.name }} {%- if item.children -%} <ul>{{ loop(item.children) }}</ul> {%- endif %}</li> {% endif %} {%- endfor %} </ul> </div> <div class="right_frame"> <iframe name="iframe1"></iframe> </div> </div> </body> </html>
You can refer to King Reload 's answer for an analysis of what I changed in the template.html file to make this work correctly.
And here is the demo_app.py script that serves my HTML HTML documents via Flask:
import threading import os import webbrowser from flask import Flask, render_template, send_from_directory app = Flask(__name__, static_folder='static') ROOT = os.path.dirname(os.path.abspath(__file__)) DOCS_ROOT = os.path.join(app.static_folder, 'docs') @app.route('/') def docs_tree(): return render_template('template.html', tree=make_tree(DOCS_ROOT)) @app.route('/docs/<path:filename>') def send_docs(filename): return send_from_directory(directory=DOCS_ROOT, 'docs'), filename=filename) def make_tree(path): tree = dict(name=os.path.basename(path), children=[]) try: lst = os.listdir(path) except OSError: pass
The most noticeable changes to demo_app.py after demo_app.py my original question were as follows:
- After initializing the
app I set DOCS_ROOT using app.static_folder ; - In the
send_docs() function, I changed the send_from_directory() directory argument to use DOCS_ROOT ; Inside make_tree() inside the else block of the for loop, I added:
np = os.path.join(path.replace(DOCS_ROOT, ''), name).replace('\\', '/') if np.startswith('/'): np = np[1:]
All this makes the absolute path name , removes what matches DOCS_ROOT , leaving only the relative path (and then replacing \\ for / ), which leads to a simple relative path from static/docs . If the relative path starts with a / , I delete it (since there is a final / from docs in template.html .
For anyone interested in the simplified style sheet ( static\styles.css ), I used (along with some updated improvements):
html { min-height:100%; position:relative; } body { overflow:hidden; } .container { width:100%; overflow:auto; } .left_frame { float:left; background:#E8F1F5; width:25%; height:100vh; } .right_frame { float:right; background:#FAFAFA; width:75%; height:100vh; } .right_frame iframe { display:block; width:100%; height:100%; border:none; }