1
0
mirror of https://github.com/webrecorder/pywb.git synced 2025-03-15 00:03:28 +01:00

ui/templates: fixes based on feedback from @ldko!

templates: add placeholder templates (footer.html, head.html)
templates: allow 'base_html', 'footer_html', 'head_html', 'header_html' to be added via wb-manager 'add-template' cmd
ui: fix logo path, support linking
ui: make url on banner an input field
docs: clarify docs around templates, paths
This commit is contained in:
Ilya Kreymer 2022-01-23 17:55:24 -08:00 committed by Tessa Walsh
parent 29860bcb24
commit 6260b226ce
16 changed files with 121 additions and 39 deletions

View File

@ -60,6 +60,15 @@ When using the custom banner, it is possible to configure a logo by setting ``ui
If omitted, the standard pywb logo will be used by default.
If set, the logo should point to a file in the static directory (default is ``static`` but can be changed via the ``static_dir`` config option).
For example, to use the file ``./static/my-logo.png`` as the logo, set:
.. code:: yaml
ui:
logo: my-logo.png
Updating the Vue UI
-------------------

View File

@ -61,6 +61,9 @@ can also be overriden:
* ``footer.html`` -- Template for adding content as the "footer" of the ``<body>`` tag of the ``base`` template
Note: The default pywb ``head.html`` and ``footer.html`` are currently blank. They can be populated to customize the rendering, add analytics, etc... as needed.
The ``base.html`` template also provides five blocks that can be supplied by templates that extend it.
* ``title`` -- Block for supplying the title for the page
@ -157,7 +160,7 @@ Template variables:
* ``{{ ui }}`` - an optional ``ui`` dictionary from ``config.yaml``, if any
* ``{{ static_prefix }}`` - the prefix from which static files will be accessed from, e.g. ``http://localhost:8080/static/``
* ``{{ static_prefix }}`` - the prefix from which static files will be accessed from, e.g. ``http://localhost:8080/static/``.
Replay and Banner Templates
@ -186,6 +189,8 @@ Template variables:
* ``{{ wb_prefix }}`` - the collection prefix, e.g. ``http://localhost:8080/pywb/``
* ``{{ host_prefix }}`` - the pywb server origin, e.g. ``http://localhost:8080``
* ``{{ config }}`` - provides the contents of the ``config.yaml`` as a dictionary.
* ``{{ ui }}`` - an optional ``ui`` dictionary from ``config.yaml``, if any.
@ -232,10 +237,10 @@ Template variables:
* ``{{ wb_url }}`` - A complete ``WbUrl`` object, which contains the ``url``, ``timestamp`` and ``mod`` properties, representing the replay url.
* ``{{ is_framed }}`` - true/false if currently in framed mode.
* ``{{ wb_prefix }}`` - the collection prefix, e.g. ``http://localhost:8080/pywb/``
* ``{{ is_proxy }}`` - set to true if page is being loaded via an HTTP/S proxy (checks if WSGI env has ``wsgiprox.proxy_host`` set)
.. _custom-top-frame:
@ -332,7 +337,7 @@ The following template variables are available to all templates.
* ``{{ env.pywb_proxy_magic }}`` - if set, indicates pywb is accessed via proxy. See :ref:`https-proxy`
* ``{{ static_prefix }}`` - path to use for loading static files.
* ``{{ static_prefix }}`` - URL path to use for loading static files.
UI Configuration

View File

@ -25,12 +25,13 @@ To enable the logo set the ``ui.logo`` property in ``config.yaml`` to point to t
The URL can be any image URL, including a URL served from the static directory.
For example, to add the default pywb logo to the banner, use the following in the config:
For example, to add the default pywb logo to the banner, use the following in the config, which will
load the logo from ``./static/pywb-logo-sm.png``
.. code:: yaml
ui:
logo: /static/pywb-logo-sm.png
logo: pywb-logo-sm.png
New Vue-based UI (Alpha)
@ -66,7 +67,7 @@ It is possible to change these settings via ``config.yaml``:
* ``static_prefix`` - sets the URL path used in pywb to serve static content (default ``static``)
* ``static_dir`` - sets the directory name used to read static files (default ``static``)
* ``static_dir`` - sets the directory name used to read static files on disk (default ``static``)
While pywb can serve static files, it is recommended to use an existing web server to serve static files, especially if already using it in production.

View File

@ -15,6 +15,11 @@ banner_html: banner.html
head_insert_html: head_insert.html
frame_insert_html: frame_insert.html
base_html: base.html
header_html: header.html
footer_html: footer.html
head_html: head.html
query_html: query.html
search_html: search.html
not_found_html: not_found.html
@ -39,6 +44,12 @@ html_templates:
- not_found_html
- home_html
- base_html
- header_html
- head_html
- footer_html
- error_html
- proxy_cert_download_html
- proxy_select_html

View File

@ -237,17 +237,20 @@ directory structure expected by pywb
v = defaults[n]
print('- {0}: (pywb/{1})'.format(n, v))
def _confirm_overwrite(self, full_path, msg):
def _confirm_overwrite(self, full_path, msg, ignore=False):
if not os.path.isfile(full_path):
return True
if ignore:
return False
res = get_input(msg)
try:
res = strtobool(res)
except ValueError:
res = False
if not res:
if not res and not ignore:
raise IOError('Skipping, {0} already exists'.format(full_path))
def _get_template_path(self, template_name, verb):
@ -268,7 +271,7 @@ directory structure expected by pywb
return full_path, filename
def add_template(self, template_name, force=False):
def add_template(self, template_name, force=False, ignore=False):
full_path, filename = self._get_template_path(template_name, 'add')
msg = ('Template file "{0}" ({1}) already exists. ' +
@ -276,7 +279,11 @@ directory structure expected by pywb
msg = msg.format(full_path, template_name)
if not force:
self._confirm_overwrite(full_path, msg)
res = self._confirm_overwrite(full_path, msg, ignore)
if ignore and not res:
return
os.makedirs(os.path.dirname(full_path), exist_ok=True)
data = resource_string('pywb', filename)
with open(full_path, 'w+b') as fh:
@ -286,6 +293,9 @@ directory structure expected by pywb
msg = 'Copied default template "{0}" to "{1}"'
print(msg.format(filename, full_path))
if template_name != "base_html":
self.add_template("base_html", force=False, ignore=True)
def remove_template(self, template_name, force=False):
full_path, filename = self._get_template_path(template_name, 'remove')

View File

@ -164,8 +164,9 @@ This file is part of pywb, https://github.com/webrecorder/pywb
logo.setAttribute("class", "_wb_linked_logo");
var logoContents = "";
logoContents += "<img src='" + window.banner_info.logoImg + "' alt='" + window.banner_info.logoAlt + "'>";
logoContents += "<img src='" + window.banner_info.logoImg + "' class='_wb_mobile' alt='" + window.banner_info.logoAlt + "'>";
var logoUrl = window.banner_info.staticPrefix + "/" + window.banner_info.logoImg;
logoContents += "<img src='" + logoUrl + "' alt='" + window.banner_info.logoAlt + "'>";
logoContents += "<img src='" + logoUrl + "' class='_wb_mobile' alt='" + window.banner_info.logoAlt + "'>";
logo.innerHTML = logoContents;
this.banner.appendChild(logo);

File diff suppressed because one or more lines are too long

View File

@ -34,7 +34,7 @@ window.banner_info = {
<link rel='stylesheet' href='{{ static_prefix }}/vue_banner.css'/>
<script src="{{ static_prefix }}/vue/vueui.js"></script>
<script>
VueUI.main("{{ static_prefix }}", "{{ url }}", "{{ wb_prefix }}", "{{ timestamp }}");
VueUI.main("{{ static_prefix }}", "{{ url }}", "{{ wb_prefix }}", "{{ timestamp }}", "{{ ui.logo }}");
</script>
{% if ui.vue_timeline_banner %}

View File

@ -0,0 +1,2 @@
{# place content to be added at the very end of the <body> tag in this file below #}

1
pywb/templates/head.html Normal file
View File

@ -0,0 +1 @@
{# place optional content to be injected into the <head> of every page in this file below #}

View File

@ -1,3 +1,4 @@
{# place content to be added at the very beginning of the <body> tag in this file below #}
<header>
{% if not err_msg and locales|length > 1 %}
<div class="language-select">

View File

@ -10,7 +10,7 @@
{% for route in routes %}
<li>
<a href="{{ env['pywb.app_prefix'] + ('/' + env.pywb_lang if env.pywb_lang else '') + '/' + route }}">{{ '/' + route }}</a>
{% if all_metadata and all_metadata[route] %}
{% if all_metadata and all_metadata[route] and all_metadata[route].title %}
({{ all_metadata[route].title }})
{% endif %}
</li>

View File

@ -75,7 +75,7 @@
renderCal.init();
{% else %}
VueUI.main("{{ static_prefix }}", "{{ url }}", "{{ prefix }}");
VueUI.main("{{ static_prefix }}", "{{ url }}", "{{ prefix }}", undefined, "{{ ui.logo }}");
{% endif %}

View File

@ -1,4 +1,4 @@
__version__ = '2.6.9'
__version__ = '2.7.0b1'
if __name__ == '__main__':
print(__version__)

View File

@ -2,7 +2,7 @@
<div class="app" :class="{expanded: showTimelineView}" data-app="webrecorder-replay-app">
<div class="banner">
<div class="line">
<div class="logo"><img :src="config.logoImg" /></div>
<div class="logo"><a href="/"><img :src="config.logoImg" style="max-width: 80px" /></a></div>
<div class="timeline-wrap">
<div class="line">
<div class="breadcrumbs-wrap">
@ -35,13 +35,15 @@
</div>
</div>
<div class="snapshot-title">
<div>{{ config.url }}</div>
<form @submit="gotoUrl">
<input id="theurl" type="text" :value="config.url"></input>
</form>
<div v-if="currentSnapshot && !showFullView">
<span v-if="config.title">{{ config.title }}</span>
Current capture: {{currentSnapshot.getTimeDateFormatted()}}
</div>
</div>
<CalendarYear v-if="showFullView"
<CalendarYear v-if="showFullView && currentPeriod && currentPeriod.children.length"
:period="currentPeriod"
:current-snapshot="currentSnapshot"
@goto-period="gotoPeriod">
@ -124,6 +126,13 @@ export default {
this.$emit("show-snapshot", snapshot);
this.showFullView = false;
},
gotoUrl(event) {
event.preventDefault();
const newUrl = document.querySelector("#theurl").value;
if (newUrl !== this.url) {
window.location.href = this.config.prefix + "*/" + newUrl;
}
},
init() {
this.config.url = this.config.initialView.url;
if (this.config.initialView.title) {
@ -134,8 +143,10 @@ export default {
this.showTimelineView = true;
} else {
this.showFullView = false;
this.showFullView = true;
this.setSnapshot(this.config.initialView);
this.showTimelineView = true;
if (this.currentPeriod.children.length) {
this.setSnapshot(this.config.initialView);
}
}
if (window.sessionStorage) {
const currentPeriodId = window.sessionStorage.getItem(this.sessionStorageUrlKey);
@ -242,4 +253,7 @@ export default {
font-weight: bold;
font-size: 16px;
}
#theurl {
width: 400px;
}
</style>

View File

@ -6,16 +6,17 @@ import Vue from "vue/dist/vue.esm.browser";
// ===========================================================================
export function main(staticPrefix, url, prefix, timestamp) {
new CDXLoader(staticPrefix, url, prefix, timestamp);
export function main(staticPrefix, url, prefix, timestamp, logoUrl) {
new CDXLoader(staticPrefix, url, prefix, timestamp, logoUrl);
}
// ===========================================================================
class CDXLoader {
constructor(staticPrefix, url, prefix, timestamp) {
constructor(staticPrefix, url, prefix, timestamp, logoUrl) {
this.opts = {};
this.prefix = prefix;
this.staticPrefix = staticPrefix;
this.logoUrl = logoUrl;
this.isReplay = (timestamp !== undefined);
@ -44,8 +45,7 @@ class CDXLoader {
this.opts.initialView = {url, timestamp};
// TODO: make configurable
this.opts.logoImg = staticPrefix + "/pywb-logo-sm.png";
this.opts.logoImg = this.staticPrefix + "/" + (this.logoUrl ? this.logoUrl : "pywb-logo-sm.png");
this.loadCDX(queryURL).then((cdxList) => {
this.app = this.initApp(cdxList, this.opts, (snapshot) => this.loadSnapshot(snapshot));
@ -60,7 +60,7 @@ class CDXLoader {
app.$set(app, "snapshots", pywbData.snapshots);
app.$set(app, "currentPeriod", pywbData.timeline);
app.$set(app, "config", {...app.config, ...config});
app.$set(app, "config", {...app.config, ...config, prefix: this.prefix});
app.$mount("#app");