From 10d1772a2d7a14c977e8359e3df25a2a40948daa Mon Sep 17 00:00:00 2001 From: Daniel Fichtinger Date: Sun, 13 Jul 2025 17:31:25 -0400 Subject: [PATCH] added config option for preview scroll tolerance --- README.md | 328 +++++++++++++++++---------------- src/zona/cli.py | 19 +- src/zona/config.py | 12 ++ src/zona/data/server/inject.js | 5 +- src/zona/server.py | 28 ++- 5 files changed, 217 insertions(+), 175 deletions(-) diff --git a/README.md b/README.md index 9ae4ef4..df3c866 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,22 @@

zona

-[zona](https://sr.ht/~ficd/zona) is an _opinionated_ static site generator -written in Python. From a structured directory of Markdown content, zona -builds a simple static website. It's designed to get out of your way and -let you focus on writing. +[zona](https://git.ficd.sh/ficd/zona) is an _opinionated_ static site generator +written in Python. From a structured directory of Markdown content, zona builds +a simple static website. It's designed to get out of your way and let you focus +on writing. -**What do I mean by opinionated?** I built zona primarily for myself. I've -tried making it flexible by exposing as many variables as possible to the -template engine. However, if you're looking for something stable, -complete, and fully configurable, zona may not be for you. If you want a -minimal Markdown blog and are comfortable with modifying `jinja2` -templates and CSS, then you're in luck. +**What do I mean by opinionated?** I built zona primarily for myself. I've tried +making it flexible by exposing as many variables as possible to the template +engine. However, if you're looking for something stable, complete, and fully +configurable, zona may not be for you. If you want a minimal Markdown blog and +are comfortable with modifying `jinja2` templates and CSS, then you're in luck. -**Note:** This project is in early development, there are no versioned -releases yet, and breaking changes are likely. Versioned releases will be -made and zona will be published to PyPI once it's stable. zona was -previously implemented in Go; I decided to rewrite the project in Python. -If you're interested in seeing the previous codebase (which is feature -incomplete), visit the [~ficd/zona-go](https://git.sr.ht/~ficd/zona-go) -repository. +**Note:** This project is in early development, there are no versioned releases +yet, and breaking changes are likely. Versioned releases will be made and zona +will be published to PyPI once it's stable. zona was previously implemented in +Go; I decided to rewrite the project in Python. If you're interested in seeing +the previous codebase (which is feature incomplete), visit the +[zona-go](https://git.ficd.sh/ficd/zona-go) repository. For an example of a website built with zona, please see [ficd.sh](https://ficd.sh). @@ -31,6 +29,7 @@ For an example of a website built with zona, please see - [Getting Started](#getting-started) - [Building](#building) - [Live Preview](#live-preview) + - [Live Reload](#live-reload) - [How It Works](#how-it-works) - [Site Layout](#site-layout) - [Templates](#templates) @@ -60,15 +59,15 @@ For an example of a website built with zona, please see - Easily configurable sitemap header. - Site footer written in Markdown. - Smart site layout discovery. - - Blog posts are automatically discovered and rendered accordingly (can - be overridden in frontmatter). + - Blog posts are automatically discovered and rendered accordingly (can be + overridden in frontmatter). - Extended Markdown renderer: - Smart internal link resolution. - Syntax highlighting. - Includes Kakoune syntax and [Ashen] highlighting. - [Image labels](#image-labels). - - Many `python-markdown` extensions enabled, including footnotes, - tables, abbreviations, etc. + - Many `python-markdown` extensions enabled, including footnotes, tables, + abbreviations, etc. - LaTeX support. ## Installation @@ -77,7 +76,7 @@ zona is not yet packaged on PyPI. You may use `uv` to install it from this repository: ```sh -uv tool install 'git+https://git.sr.ht/~ficd/zona' +uv tool install 'git+https://git.ficd.sh/ficd/zona' ``` ## Usage @@ -87,71 +86,78 @@ available options and arguments._ ### Getting Started -To set up a new website, create a new directory and run `zona init` inside -of it. This creates the required directory structure and writes the -default configuration file. The default templates and default stylesheet -are also written. +To set up a new website, create a new directory and run `zona init` inside of +it. This creates the required directory structure and writes the default +configuration file. The default templates and default stylesheet are also +written. ### Building -To build the website, run `zona build`. The project root is discovered -according to the location of `config.yml`. By default, the output -directory is called `public`, and saved inside the root directory. +To build the website, run `zona build`. The project root is discovered according +to the location of `config.yml`. By default, the output directory is called +`public`, and saved inside the root directory. If you don't want discovery, you can specify the project root as the first argument to `zona build`. You may specify a path for the output using the -`--output/-o` flag. The `--draft/-d` flag includes draft posts in the -output. +`--output/-o` flag. The `--draft/-d` flag includes draft posts in the output. -_Note: the previous build is _not_ cleaned before the new site is built. -If you've deleted some pages, you may need to remove the output directory -before rebuilding._ +_Note: the previous build is _not_ cleaned before the new site is built. If +you've deleted some pages, you may need to remove the output directory before +rebuilding._ ### Live Preview -To make the writing process as frictionless as possible, zona ships with a -live preview server. It spins up an HTTP server, meaning that internal -links work properly (this is not the case if you simply open the `.html` -files in your browser.) +To make the writing process as frictionless as possible, zona ships with a live +preview server. It spins up an HTTP server, meaning that internal links work +properly (this is not the case if you simply open the `.html` files in your +browser.) -Additionally, the server watches for changes to all source files, and -rebuilds the website when they're modified. _Note: the entire website is -rebuilt — this ensures that links are properly resolved._ +Additionally, the server watches for changes to all source files, and rebuilds +the website when they're modified. _Note: the entire website is rebuilt — this +ensures that links are properly resolved._ -Optionally, live reloading of the browser is also provided. With this -feature (enabled by default), your browser will automatically refresh open -pages whenever the site is rebuilt. The live reloading requires JavaScript -support from the browser — this is why the feature is optional. +Drafts are enabled by default in live preview. Use `--final/-f` to disable them. +By default, the build outputs to a temporary directory. Use `-o/--output` to +override this. -To start a preview server, use `zona serve`. You can specify the root -directory as its first argument. Use the `--host` to specify a host name -(`localhost` by default) and `--port/-p` to specify a port (default: -`8000`). The `--no-live-reload/-n` disables the live browser reloading -(_automatic site rebuilds are not disabled_). +**Note**: if the live preview isn't working as expected, try restarting the +server. If you change the configuration or any templates, the server must also +be restarted. The live preview uses the same function as `zona build` +internally; this means that the output is also written to disk. -Drafts are enabled by default in live preview. Use `--final/-f` to disable -them. By default, the build outputs to a temporary directory. Use -`-o/--output` to override this. +#### Live Reload -**Note**: if the live preview isn't working as expected, try restarting -the server. If you change the configuration or any templates, the server -must also be restarted. The live preview uses the same function as -`zona build` internally; this means that the output is also written to -disk. +Optionally, live reloading of the browser is also provided. With this feature +(enabled by default), your browser will automatically refresh open pages +whenever the site is rebuilt. The live reloading requires JavaScript support +from the browser — this is why the feature is optional. + +To start a preview server, use `zona serve`. You can specify the root directory +as its first argument. Use the `--host` to specify a host name (`localhost` by +default) and `--port/-p` to specify a port (default: `8000`). + +The `--live-reload/--no-live-reload` option overrides the value set in the +[config](#configuration) (`true` by default). _Automatic site rebuilds are not +affected_. + +If you are scrolled to the bottom of the page in the browser, and you extend the +height of the page by adding new content, you will automatically be scrolled to +the _new_ bottom after reloading. You may tune the tolerance threshold in the +[configuration](#configuration). #### How It Works -The basic idea is this: after a rebuild, the server needs to notify your -browser to refresh the open pages. We implement this using a small amount -of JavaScript. The server injects a tiny script into any HTML page it -serves; which causes your browser to open a WebSocket connection with the -server. When the site is rebuilt, the server notifies your browser via the -WebSocket, which reloads the page. +The basic idea is this: after a rebuild, the server needs to notify your browser +to refresh the open pages. We implement this using a small amount of JavaScript. +The server injects a tiny script into any HTML page it serves; which causes your +browser to open a WebSocket connection with the server. When the site is +rebuilt, the server notifies your browser via the WebSocket, which reloads the +page. Unfortunately, there is no way to implement this feature without using -JavaScript. **JavaScript is _only_ used for the live preview feature. The -script is injected by the server, and never written to the HTML files in -the output directory.** +JavaScript. **JavaScript is _only_ used for the live preview feature. The script +is injected by the server, and never written to the HTML files in the output +directory.** ### Site Layout @@ -164,32 +170,30 @@ templates/ public/ ``` -The **root** of the zona **project** _must_ contain the configuration -file, `config.yml`, and a directory called `content`. A directory called -`templates` is optional, and prioritized if it exists. `public` is the -built site output — it's recommended to add this path to your -`.gitignore`. +The **root** of the zona **project** _must_ contain the configuration file, +`config.yml`, and a directory called `content`. A directory called `templates` +is optional, and prioritized if it exists. `public` is the built site output — +it's recommended to add this path to your `.gitignore`. The `content` directory is the **root of the website**. Think of it as the -**content root**. For example, suppose your website is hosted at -`example.com`. `content/blog/index.md` corresponds to `example.com/blog`, +**content root**. For example, suppose your website is hosted at `example.com`. +`content/blog/index.md` corresponds to `example.com/blog`, `content/blog/my-post.md` becomes `example.com/blog/my-post`, etc. - Internal links are resolved **relative to the `content` directory.** - Templates are resolved relative to the `template` directory. Markdown files inside a certain directory (`content/blog` by default) are -automatically treated as _blog posts_. This means they are rendered with -the `page` template, and included in the `post_list`, which can be -included in your site using the `post_list` template. +automatically treated as _blog posts_. This means they are rendered with the +`page` template, and included in the `post_list`, which can be included in your +site using the `post_list` template. ### Templates The `templates` directory may contain any `jinja2` template files. You may -modify the existing templates or create your own. To apply a certain -template to a page, set the `template` option in its -[frontmatter](#frontmatter). The following public variables are made -available to the template engine: +modify the existing templates or create your own. To apply a certain template to +a page, set the `template` option in its [frontmatter](#frontmatter). The +following public variables are made available to the template engine: | Name | Description | | ---------- | ------------------------------------------------------ | @@ -201,43 +205,40 @@ available to the template engine: #### Markdown Footer -The `templates` directory can contain a file called `footer.md`. If it -exists, it's parsed and rendered into HTML, then made available to other -templates as the `footer` variable. If `footer.md` is missing but -`footer.html` exists, then it's used instead. **Note: links are _not_ -resolved in the footer.** +The `templates` directory can contain a file called `footer.md`. If it exists, +it's parsed and rendered into HTML, then made available to other templates as +the `footer` variable. If `footer.md` is missing but `footer.html` exists, then +it's used instead. **Note: links are _not_ resolved in the footer.** ### Internal Link Resolution -When zona encounters links in Markdown documents, it attempts to resolve -them as internal links. Links beginning with `/` are resolved relative to -the content root; otherwise, they are resolved relative to the Markdown -file. If the link resolves to an existing file that is part of the -website, it's replaced with an appropriate web-server-friendly link. -Otherwise, the link isn't changed. +When zona encounters links in Markdown documents, it attempts to resolve them as +internal links. Links beginning with `/` are resolved relative to the content +root; otherwise, they are resolved relative to the Markdown file. If the link +resolves to an existing file that is part of the website, it's replaced with an +appropriate web-server-friendly link. Otherwise, the link isn't changed. -For example, suppose the file `blog/post1.md` has a link `./post2.md`. The -HTML output will contain the link `/blog/post2` (which corresponds to -`/blog/post2/index.html`). Link resolution is applied to _all_ internal -links, including those pointing to static resources like images. Links are -only modified if they point to a real file that's not included in the -ignore list. +For example, suppose the file `blog/post1.md` has a link `./post2.md`. The HTML +output will contain the link `/blog/post2` (which corresponds to +`/blog/post2/index.html`). Link resolution is applied to _all_ internal links, +including those pointing to static resources like images. Links are only +modified if they point to a real file that's not included in the ignore list. ### Syntax Highlighting -Zona uses [Pygments] to provide syntax highlighting for fenced code -blocks. The following Pygments plugins are included: +Zona uses [Pygments] to provide syntax highlighting for fenced code blocks. The +following Pygments plugins are included: -- [pygments-kakoune](https://git.sr.ht/~ficd/pygments-kakoune) - - A lexer providing for highlighting Kakoune code. Available under the - `kak` and `kakrc` aliases. -- [pygments-ashen](https://git.sr.ht/~ficd/ashen/tree/main/item/pygments/README.md) - - An implementation of the [Ashen](https://git.sr.ht/~ficd/ashen) theme - for Pygments. +- [pygments-kakoune](https://codeberg.com/ficd/pygments-kakoune) + - A lexer providing for highlighting Kakoune code. Available under the `kak` + and `kakrc` aliases. +- [pygments-ashen](https://codeberg.com/ficd/ashen/tree/main/item/pygments/README.md) + - An implementation of the [Ashen](https://codeberg.com/ficd/ashen) theme for + Pygments. If you want to use any external Pygments styles or lexers, they must be -available in zona's Python environment. For example, you can give zona -access to [Catppucin](https://github.com/catppuccin/python): +available in zona's Python environment. For example, you can give zona access to +[Catppucin](https://github.com/catppuccin/python): ```yaml # config.yml @@ -252,9 +253,9 @@ Then, run zona with the following `uv` command: uvx --with catppucin zona build ``` -Inline syntax highlighting is also provided via a `python-markdown` -extension. If you prefix inline code with a shebang followed by the -language identifier, it will be highlighted. For example: +Inline syntax highlighting is also provided via a `python-markdown` extension. +If you prefix inline code with a shebang followed by the language identifier, it +will be highlighted. For example: ``` `#!python print(f"I love {foobar}!", end="")` @@ -280,10 +281,9 @@ will be rendered as ### Image Labels -A feature unique to zona is **image labels**. They make it easy to -annotate images in your Markdown documents. The alt text Markdown element -is rendered as the label — with support for inline Markdown. Consider this -example: +A feature unique to zona is **image labels**. They make it easy to annotate +images in your Markdown documents. The alt text Markdown element is rendered as +the label — with support for inline Markdown. Consider this example: ```markdown ![This **image** has _markup_.](static/markdown.png) @@ -298,14 +298,14 @@ The above results in the following HTML: ``` The `image-container` class is provided as a convenience for styling. The -default stylesheet centers the label under the image. Note: _links_ inside -image captions are not currently supported. I am looking into a solution. +default stylesheet centers the label under the image. Note: _links_ inside image +captions are not currently supported. I am looking into a solution. ### Frontmatter -YAML frontmatter can be used to configure the metadata of documents. All -of them are optional. `none` is used when the option is unset. The -following options are available: +YAML frontmatter can be used to configure the metadata of documents. All of them +are optional. `none` is used when the option is unset. The following options are +available: | Key | Type & Default | Description | | ------------ | --------------------------------- | ------------------------------------------------------------------------------------------------------ | @@ -338,10 +338,9 @@ template: post_list Welcome to my blog! Please find a list of my posts below. ``` -Setting `post: false` is necessary because, by default, all documents -inside `content/blog` are considered to be posts unless explicitly -disabled in the frontmatter. We don't want the post list to list _itself_ -as a post. +Setting `post: false` is necessary because, by default, all documents inside +`content/blog` are considered to be posts unless explicitly disabled in the +frontmatter. We don't want the post list to list _itself_ as a post. Then, you'd create `content/blog/my-post.md` and populate it: @@ -352,32 +351,32 @@ date: July 5, 2025 --- ``` -Because `my-post` is inside the `blog` directory, `post: true` is implied. -If you wanted to put it somewhere outside `blog`, you would need to set +Because `my-post` is inside the `blog` directory, `post: true` is implied. If +you wanted to put it somewhere outside `blog`, you would need to set `post: true` for it to be included in the post list. ## Configuration -Zona is configured in YAML format. The configuration file is called -`config.yml` and it **must** be located in the root of the project — in -the same directory as `content` and `templates`. +Zona is configured in YAML format. The configuration file is called `config.yml` +and it **must** be located in the root of the project — in the same directory as +`content` and `templates`. -Your configuration will be merged with the defaults. `zona init` also -writes a copy of the default configuration to the correct location. If it -exists, you'll be prompted before overwriting it. +Your configuration will be merged with the defaults. `zona init` also writes a +copy of the default configuration to the correct location. If it exists, you'll +be prompted before overwriting it. -**Note:** Currently, not every configuration value is actually used. Only -the useful settings are listed here. +**Note:** Currently, not every configuration value is actually used. Only the +useful settings are listed here. Please see the default configuration: ```yaml +base_url: / sitemap: Home: / ignore: - .marksman.toml markdown: - image_labels: true tab_length: 2 syntax_highlighting: enabled: true @@ -385,49 +384,60 @@ markdown: wrap: false links: external_new_tab: true +build: + clean_output_dir: true + include_drafts: false blog: dir: blog +server: + reload: + enabled: true + scroll_tolerance: 100 ``` -| Name | Description | -| -------------------------------------- | --------------------------------------------------------------------------------------------- | -| `sitemap` | Sitemap dictionary. See [Sitemap](#sitemap). | -| `ignore` | List of paths to ignore. See [Ignore List](#ignore-list). | -| `markdown.tab_length` | How many spaces should be considered an indentation level. | -| `markdown.syntax_highlighting.enabled` | Whether code should be highlighted. | -| `markdown.syntax_highlighting.theme` | [Pygments] style for highlighting. | -| `markdown.syntax_highlighting.wrap` | Whether the resulting code block should be word wrapped. | -| `markdown.links.external_new_tab` | Whether external links should be opened in a new tab. | -| `blog.dir` | Name of a directory relative to `content/` whose children are automatically considered posts. | +| Name | Description | +| -------------------------------------- | ----------------------------------------------------------------------------------------------- | +| `sitemap` | Sitemap dictionary. See [Sitemap](#sitemap). | +| `ignore` | List of paths to ignore. See [Ignore List](#ignore-list). | +| `markdown.tab_length` | How many spaces should be considered an indentation level. | +| `markdown.syntax_highlighting.enabled` | Whether code should be highlighted. | +| `markdown.syntax_highlighting.theme` | [Pygments] style for highlighting. | +| `markdown.syntax_highlighting.wrap` | Whether the resulting code block should be word wrapped. | +| `markdown.links.external_new_tab` | Whether external links should be opened in a new tab. | +| `build.clean_output_dir` | Whether previous build artifacts should be cleared when building. Recommended to leave this on. | +| `build.include_drafts` | Whether drafts should be included by default. | +| `blog.dir` | Name of a directory relative to `content/` whose children are automatically considered posts. | +| `server.reload.enabled` | Whether the preview server should use [live reload](#live-preview). | +| `server.reload.scroll_tolerance` | The distance, in pixels, from the bottom to still count as "scrolled to bottom". | ### Sitemap -You can define a sitemap in the configuration file. This is a list of -links that will be rendered at the top of every page. The `sitemap` is a -dictionary of `string` to `string` pairs, where each key is the displayed -text of the link, and the value if the `href`. Consider this example: +You can define a sitemap in the configuration file. This is a list of links that +will be rendered at the top of every page. The `sitemap` is a dictionary of +`string` to `string` pairs, where each key is the displayed text of the link, +and the value if the `href`. Consider this example: ```yaml sitemap: Home: / About: /about Blog: /blog - Git: https://git.sr.ht/~ficd + Git: https://git.ficd.sh/ficd ``` ### Ignore List -You can set a list of glob patterns in the [configuration](#configuration) -that should be ignored by zona. This is useful because zona makes a copy -of _every_ file it encounters inside the `content` directory, regardless -of its type. The paths must be relative to the `content` directory. +You can set a list of glob patterns in the [configuration](#configuration) that +should be ignored by zona. This is useful because zona makes a copy of _every_ +file it encounters inside the `content` directory, regardless of its type. The +paths must be relative to the `content` directory. ### Drafts -zona allows you to begin writing content without including it in the final -build output. If you set `draft: true` in a page's frontmatter, it will be -marked as a draft. Drafts are completely excluded from `zona build` and -`zona serve` unless the `--draft` flag is specified. +zona allows you to begin writing content without including it in the final build +output. If you set `draft: true` in a page's frontmatter, it will be marked as a +draft. Drafts are completely excluded from `zona build` and `zona serve` unless +the `--draft` flag is specified. -[Ashen]: https://sr.ht/~ficd/ashen +[Ashen]: https://codeberg.com/ficd/ashen [Pygments]: https://pygments.org/ diff --git a/src/zona/cli.py b/src/zona/cli.py index 1d32c4c..a7e2dd5 100644 --- a/src/zona/cli.py +++ b/src/zona/cli.py @@ -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, ) diff --git a/src/zona/config.py b/src/zona/config.py index 4bd7a42..cc56ec2 100644 --- a/src/zona/config.py +++ b/src/zona/config.py @@ -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": diff --git a/src/zona/data/server/inject.js b/src/zona/data/server/inject.js index d199c03..bc00dde 100644 --- a/src/zona/data/server/inject.js +++ b/src/zona/data/server/inject.js @@ -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"); } diff --git a/src/zona/server.py b/src/zona/server.py index b2e0a64..23c4c0b 100644 --- a/src/zona/server.py +++ b/src/zona/server.py @@ -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"" @@ -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: