added config option for preview scroll tolerance
This commit is contained in:
parent
fe0f338803
commit
10d1772a2d
5 changed files with 217 additions and 175 deletions
|
@ -95,14 +95,15 @@ def serve(
|
|||
bool,
|
||||
typer.Option("--final", "-f", help="Don't include drafts."),
|
||||
] = False,
|
||||
no_live_reload: Annotated[
|
||||
bool,
|
||||
live_reload: Annotated[
|
||||
bool | None,
|
||||
typer.Option(
|
||||
"--no-live-reload",
|
||||
"-n",
|
||||
help="Don't automatically reload web preview.",
|
||||
"--live-reload/--no-live-reload",
|
||||
"-l/-L",
|
||||
help="Automatically reload web preview. Overrides config.",
|
||||
show_default=False,
|
||||
),
|
||||
] = False,
|
||||
] = None,
|
||||
):
|
||||
"""
|
||||
Build the website and start a live preview server.
|
||||
|
@ -115,13 +116,17 @@ def serve(
|
|||
print("Preview without drafts.")
|
||||
else:
|
||||
print("Preview with drafts.")
|
||||
if live_reload is None:
|
||||
reload = None
|
||||
else:
|
||||
reload = live_reload
|
||||
server.serve(
|
||||
root=root,
|
||||
output=output,
|
||||
draft=not final,
|
||||
host=host,
|
||||
port=port,
|
||||
live_reload=not no_live_reload,
|
||||
user_reload=reload,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -58,6 +58,17 @@ class BuildConfig:
|
|||
include_drafts: bool = False
|
||||
|
||||
|
||||
@dataclass
|
||||
class ReloadConfig:
|
||||
enabled: bool = True
|
||||
scroll_tolerance: int = 100
|
||||
|
||||
|
||||
@dataclass
|
||||
class ServerConfig:
|
||||
reload: ReloadConfig = field(default_factory=ReloadConfig)
|
||||
|
||||
|
||||
IGNORELIST = [".marksman.toml"]
|
||||
|
||||
|
||||
|
@ -71,6 +82,7 @@ class ZonaConfig:
|
|||
markdown: MarkdownConfig = field(default_factory=MarkdownConfig)
|
||||
build: BuildConfig = field(default_factory=BuildConfig)
|
||||
blog: BlogConfig = field(default_factory=BlogConfig)
|
||||
server: ServerConfig = field(default_factory=ServerConfig)
|
||||
|
||||
@classmethod
|
||||
def from_file(cls, path: Path) -> "ZonaConfig":
|
||||
|
|
|
@ -9,12 +9,13 @@
|
|||
});
|
||||
}
|
||||
|
||||
const ws = new WebSocket("__SOCKET_ADDRESS_");
|
||||
const ws = new WebSocket("__SOCKET_ADDRESS__");
|
||||
const tol = __SCROLL_TOLERANCE__;
|
||||
ws.onmessage = event => {
|
||||
if (event.data === "reload") {
|
||||
// store flag if user currently at bottom
|
||||
const nearBottom = window.innerHeight + window.scrollY
|
||||
>= document.body.scrollHeight - 100;
|
||||
>= document.body.scrollHeight - tol;
|
||||
if (nearBottom) {
|
||||
localStorage.setItem("wasAtBottom", "1");
|
||||
}
|
||||
|
|
|
@ -21,17 +21,22 @@ from zona.websockets import WebSocketServer
|
|||
logger = get_logger()
|
||||
|
||||
|
||||
def make_reload_script(host: str, port: int) -> str:
|
||||
def make_reload_script(
|
||||
host: str, port: int, scroll_tolerance: int
|
||||
) -> str:
|
||||
"""Generates the JavaScript that must be injected into HTML pages for the live reloading to work."""
|
||||
js = util.get_resource("server/inject.js").contents
|
||||
js = util.minify_js(js)
|
||||
address = f"ws://{host}:{port}"
|
||||
for placeholder, value in (("__SOCKET_ADDRESS_", address),):
|
||||
for placeholder, value in (
|
||||
("__SOCKET_ADDRESS__", address),
|
||||
("__SCROLL_TOLERANCE__", scroll_tolerance),
|
||||
):
|
||||
if placeholder not in js:
|
||||
raise ValueError(
|
||||
f"{placeholder} missing from reload script template!"
|
||||
)
|
||||
js = js.replace(placeholder, value)
|
||||
js = js.replace(placeholder, str(value))
|
||||
return f"<script>{js}</script>"
|
||||
|
||||
|
||||
|
@ -172,12 +177,13 @@ def serve(
|
|||
draft: bool = True,
|
||||
host: str = "localhost",
|
||||
port: int = 8000,
|
||||
live_reload: bool = True,
|
||||
user_reload: bool | None = None,
|
||||
):
|
||||
"""Serve preview website with live reload and automatic rebuild."""
|
||||
# create temp dir, automatic cleanup
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
builder = ZonaBuilder(root, Path(tmp), draft)
|
||||
config = builder.config
|
||||
# initial site build
|
||||
builder.build()
|
||||
# use discovered paths if none provided
|
||||
|
@ -186,13 +192,21 @@ def serve(
|
|||
if root is None:
|
||||
root = builder.layout.root
|
||||
|
||||
# spin up websocket server for live reloading
|
||||
if live_reload:
|
||||
# use config value unless overridden by user
|
||||
reload = config.server.reload.enabled
|
||||
if user_reload is not None:
|
||||
reload = user_reload
|
||||
if reload:
|
||||
print("Live reloading is enabled.")
|
||||
# spin up websocket server for live reloading
|
||||
ws_port = port + 1
|
||||
ws_server = WebSocketServer(host, ws_port)
|
||||
ws_server.start()
|
||||
# generate reload script for injection
|
||||
reload_script = make_reload_script(host, ws_port)
|
||||
scroll_tolerance = config.server.reload.scroll_tolerance
|
||||
reload_script = make_reload_script(
|
||||
host, ws_port, scroll_tolerance
|
||||
)
|
||||
# generate handler with reload script as attribute
|
||||
handler = make_handler_class(reload_script)
|
||||
else:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue