siteleteer A tiny, self-replicating tool for building multi-page websites in a single HTML file.


About siteleteer

**siteleteer** is a super hackable, self-replicating web app that lets you create sitelets (mini websites) with inter-linking pages formatted with [[Markdown Support|Markdown]]. All data created with **siteleteer** is simply stored directly as HTML on the page, and the code within the HTML file is not minified at all, making it easier to simply crack open in a text editor and modify however you wish!

It's page management with Markdown formatting and a simple search bar all rolled up into a single HTML file that's _less than 20 kilobytes!_

## How to Use

Just <a href="" download="siteleteer.html" target="_blank">download a blank **siteleteer** HTML file</a> and open it in a browser to get started. It's pretty simple:

- Use the "Settings" button to change the wiki's name, description, and CSS, then push "Save" to make your changes.
- Create a new page by using the "New Page" button. This will create an empty page that you can start editing right away.
	- Set a page title in the "Name" field and write some text for the page with Markdown formatting.
		- In addition to Markdown, you can link between pages using wiki link format by putting the (case-sensitive) page name in 2 square braces \[\[like this\]\]! If you want the link to have different text than the page's name, then put the page name first then the text to display after a vertical bar \[\[Other Page|like this\]\]!
	- If you have multiple pages, you can change the order they display in the navigation by changing the Sort Position.
	- The page in the `0` position will be the "home" page of your **siteleteer** that is displayed when the file loads or when the Wiki Title is clicked.
	- Use "Save" to save the page and view the page.
	- Use "Cancel" to prevent any changes from being saved (results in an empty page if it's newly created).
	- Use "Delete" to remove the page and navigation entry.
- Search for text in your pages using the Search bar. Check the Particularities below for exactly how the results are found & sorted.
- Click the "Edit" button at the bottom of a page to change that page. The date at the bottom of the page will be updated when you save your changes.
- Save your changes to a new HTML file by using the "Save" button (or <kbd>Ctrl</kbd>/<kbd>Command</kbd> + <kbd>S</kbd>). The HTML file defaults to a lowercase version of your wiki's name with any non-alphanumeric characters converted to underscores `like_this.html`.

And that's pretty much it, though you'll want to be aware of some [[Peculiarities|peculiarities]] of the system.

If you want to get an idea of how to use **siteleteer**, you can make changes to and download _this_ site by just clicking the "Save" button in the top right corner! Any changes you make will be saved as a new file on your computer, but they aren't permanent and will reset if you refresh the page.

## Changelog

- 2024-06-14 [[Upgrade Guide]]
	- Navigation is now in a `details` element labeled "Menu" that must be clicked to show the pages
	- Making a wiki link to a nonexistent page will create a new one with the specified page name
	- Saving won't navigate browser back if you're on the home page already.
- 2024-03-27
	- Fix load loop on empty siteleteer sites in Firefox
	- Search results now hide when search bar loses focus
	- Search results correctly highlight search term
- 2024-02-16
	- Version 1.0.0 is launched


Being a tiny platform with as little unnecessary functionality as possible, there are some behaviors that you should keep in mind while using it. Here's everything that might be unexpected in no particular order:

- New pages are always added to the end of the page order, and thus the end of the nav bar.
- Pages without a name cannot be linked to and display in the navigation as "No content."
- Navigating to a different page while editing will change the page _immediately_ and **discard any unsaved changes** to the page.
- Page names must be unique or else wiki links won't work unless you find and use the page's id instead of its name!
	- You can find the page's id by hovering over its nav menu item.
- If you use a wiki link to a page that doesn't exist, it will create a new page with the linked text as the title.
- When editing a page, pressing <kbd>Tab</kbd> in the Markdown Content text area (also the Wiki CSS text area in Settings) will type a `Tab` character instead of changing focus to the next form element.
	- Holding <kbd>Shift</kbd> while pressing <kbd>Tab</kbd> _will_ navigate to the previous element as expected.
- You _can_ use HTML in the wiki name and description, but should you?
- The Wiki CSS is actually the literal contents of the `<style>` tag in the HTML's head. You can change it however you wish, but it might affect the wiki's page structure if you remove too much stuff.
- Every page exists in the file's HTML, but all pages except for the current one are hidden by default.
- The "Updated" timestamp at the bottom of a page is set to _your_ local date and time.
- Hover over the "Updated" timestamp at the bottom of a page to see the timestamp of when the page was first created, i.e. the moment "New Page" was pressed.
- Search prioritizes exact matches over case-insensitive ones and will display matching pages in order by where the match is found, prioritizing page names over page text, and only the text content of the parsed Markdown is searched when looking for results within the page text.
- Very large amounts of content on a page and very large numbers of pages may affect the performance of your **siteleteer** because it just uses and manipulates the raw DOM.
- Only the Markdown of each page is saved and can be found directly in the HTML file within a `pre` tag in the page's `section` tag. It's parsed into formatted HTML that displays when the page is loaded and the JavaScript runs.
- All pages are on the same level and display in the wiki nav bar.

Markdown Support

_**Click the "Edit" button at the bottom of the page to see the Markdown source!**_


<!--This means we can use HTML elements in Markdown, such as the comment
element, and they won't be affected by a markdown parser. However, if you
create an HTML element in your markdown file, you cannot use markdown syntax
within that element's contents.-->

# This is an `<h1>`
## This is an `<h2>`
### This is an `<h3>`
#### This is an `<h4>`
##### This is an `<h5>`
###### This is an `<h6>`

This is an h1

This is an h2

*This text is in italics.*
_And so is this text._

**This text is in bold.**
__And so is this text.__

***This text is in both.***
**_As is this!_**
*__And this!__*

~~This text is rendered with strikethrough.~~

This is a paragraph. I'm typing in a paragraph isn't this fun?

Now I'm in paragraph 2.
I'm still in paragraph 2 too!

I'm in paragraph three!

I end with two spaces (highlight me to see them).

There's a `<br />`  
above me!

> This is a block quote. You can either
> manually wrap your lines and put a `>` before every line or you can let your lines get really long and wrap on their own.
> It doesn't make a difference so long as they start with a `>`.

> You can only use one level
>> of indentation?
>> Oh well!

* Item
* Item
* Another item


+ Item
+ Item
+ One more item


- Item
- Item
- One last item

- List
	- Indentation
		- also
	- works!
- (with
	- two
	- spaces)

1. Item one
2. Item two
3. Item three

1. Item one
1. Item two
1. Item three

1. Item one
2. Item two
3. Item three
	* mixing
	* Sub-list types
4. Item four

Boxes below without the 'x' are unchecked HTML checkboxes.
- [ ] First task to complete.
- [ ] Second task that needs done

This checkbox below will be a checked HTML checkbox.

- [x] This task has been completed

This is code
				So is this

function canLabelCode() {
		return true;

Here's some \<Escaped text!\>

John didn't even know what the `go_to()` function did!



- - -


[Click me!](

[Click me!]( "Link to")

[Go to music](/music/).

- [Heading](#heading)
- [Another heading](#another-heading)
- [Chapter](#chapter)
	- [Subchapter <h3 />](#subchapter-h3-)

![This is the alt-attribute for my image]( "An optional title")

<> is equivalent to


I want to type *this text surrounded by asterisks* but I don't want it to be
in italics, so I do this: \*this text surrounded by asterisks\*.

Your computer crashed? Try sending a

Hacking siteleteer

Since it's literally just an HTML file with all its code visibly formatted in the way the developer writes it, you can just change the content or behavior! All you need is a text editor and a basic understanding of web development (HTML, CSS, and JavaScript).

The only HTML altered by the app is:

- The `<a id="name">` element in the wiki header
- The `<span id="desc">` element in the wiki header
- The `<div id="results">` element in the wiki header
- The CSS within the `<style id="css">` element in the HTML `head`
- The HTML content within the `<main>` element.

Pretty much anywhere else is untouched by the JavaScript and can be modified. If you need to add meta tags to the head or additional code, you can just do that. In addition, all the app functions can be accessed through `window` in JavaScript. There are also a couple helper methods in there to keep the code small.

All the functions that control the app are set directly in the `window` and include some basic comments to help you know what everything does, and all the site data is stored directly in the HTML within `<pre>` tags as Markdown. The only thing to be aware of is that all HTML elements (i.e. `<` and `>` characters) are stored as HTML entities (i.e. `<` and `>`). If processing the Markdown outside of **siteleteer**, be sure to re-encode the HTML entities into their appropriate characters or else it may not parse properly.

## App Reference

Below are all of the functions and global variables used to make **siteleteer** function with additional details to help clarify their use:

- `add(title)`: Create a new page element & start editing. If `title` is included, it will auto-fill the title field with that value.
- `ce(tagName: string)`: Short alias of `document.getElementById`.
- `current: string`: The current page id.
- `del(pageId: string|number)`: Delete the page with the given id. Asks for confirmation before deletion.
- `edit(pageId: string|number, yes: boolean = true)`: Show (default) or hide a form to edit the page with given id. Also updates nav entry.
- `gebi(id: string)`: Short alias of `document.getElementById()`.
- `go(pageIdOrName?: string, back: boolean = false)`: Show page element with given name (case-sensitive) or id, or home page if none is given. If back == true, don't update url hash
- `h(hash?: string)`: Get and/or set the URL hash. If `hash` is set, then set the URL hash. Either way, it returns the current URL hash from `window.location.hash`.
- `handleTab()`: Sets the `onkeydown` attribute of all existing `<textarea<` elements without class `notab` to enable typing the `Tab` character when Tab is typed. If Shift is held, the focus will move to the previous focusable element instead of inserting a `Tab`.
- `info(element: HTMLElement)`: Get page details as object from the given element. Object contains the page element's `id` as a string, page `name` as a string, and `src` containing the raw Markdown content of the page.
- `main: HTMLElement`: Reference to the `<main>` HTMLElement
- `md(markdown?: string)`: Parse given Markdown into HTML. If empty, returns an empty string.
- `nav: HTMLUListElement`: Reference to the `<ul>` element within the `<nav>` in the site header.
- `navItem(element: HTMLElement)`: Given a page element, return a new `<li>` element to insert into the site nav with a link to the given page with text equal to the name of the page.
- `pages()`: Get all current page HTMLElements as an array.
- `q(selector: string, element?: HTMLElement)`: Short alias of `querySelector()`. If no `element` is provided, `document` is used by default.
- `qa(selector: string, element?: HTMLElement)`: Short alias of `document.querySelectorAll()`. If no `element` is provided, `document` is used by default.
- `render(pageId?: string)`: If `pageId` is given, re-render stored Markdown directly into the element & update nav text. Otherwise, re-render all stored Markdown into the `<main>` element and re-create the `<nav>` element.
- `res: HTMLElement`: Reference to the element where search results are displayed. If empty, the element is hidden.
- `save()`: Reset to default state, remove rendered Markdown, start download of HTML file, and then reset the display to current view.
- `sBar: HTMLInputElement`: Reference to the `<input>` element where searches are done. The element has event listeners on the `keydown` and `focus` events to run `search()` using the input value when triggered.
- `search(term: string)`: Check all pages for text matching the given term. If no results or an empty `term` are provided, the `res` element will be empty and not visible, otherwise it will display the search results.
- `settingFields()`: Get the names of all form inputs within the settings dialog. These field names are intended to match an HTMLElement id elsewhere in the HTML.
- `settings(close?: boolean)`: Show (default) or hide settings dialog. When opened, the field values are populated with the `innerHTML` of the HTMLElements with the same name as the `<input>` elements.
- `show(element: HTMLElement, yes: boolean = true)`: Show (default) or hide the given page element. Page `<section>` elements are hidden by default and displayed by setting `style="display:block"` on the element. If `yes` is set to `false`, then the `display` style is removed, hiding the page.
- `update(form: HTMLFormElement)`: Save the settings dialog & update innerHTML of all elements with ids matching the input name within the `<form>`.
- `wikiLinks(text: string)`: Parse all \[\[wiki links\]\] in the given text into HTML `<a>` tags that link to the name or id of the page within the double braces using `javascript:go()` as the `href` attribute. The link text can be set by using a vertical bar `|` to separate the page name/id and the link text \[\[other page|like this\]\].

## Ideas

- Don't want your updated time visible on a page? Find the `main>section>footer>time` entry in the Wiki CSS and add `display: none;` to hide it.
	- Don't want it in the HTML at all? Then you'll need to update the code to stop the `<time>` elements from being created and then remove them from your HTML. It's set in the `add()` method and modified in the `edit()` method.
- Need **siteleteer** in your own language? Just modify the UI text in the HTML file!
- Want to restructure the whole app? You can change the CSS and HTML completely if you need to! Just check the code for any expected structure patterns first so you don't break anything.
- Don't like the Markdown parser? Replace it! As long as whatever parser you use has its parse function set to ``, **siteleteer** should handle it fine!


If you're done working on your **siteleteer**'s content, all you really need to do to publish your work is upload the HTML file somewhere that can be accessed by a web browser. But if you want to present it in a way that looks a little more finalized, there are a few things you can do to make your finished product even better!

## Hide the Edit Buttons

The easiest way to make your **siteleteer** not immediately editable would be to simply hide the management buttons that create and edit pages. You can do that by simply adding some CSS to make them not display:

#actions :last-child,
.editBtn {
	display: none;

Keep in mind that simply hiding the buttons means that they are still present in the HTML, so if that bothers you, you might want to look into the more drastic option of _deleting_ the HTML.

The primary benefit of simply hiding the buttons is that you can un-hide them later and use them to make changes to your site as normal, but they do remain as an extra little bit of dead weight in the HTML.

## _Remove_ the Edit Buttons

This option may be a bit more dramatic than necessary since the vast majority of people aren't going to be looking at your site's raw HTML, but if you want to take that extra step, you can run the following script to remove all the edit buttons from the code:

qa('#actions :last-child, .editBtn').forEach(el => el.parentNode.removeChild(el));

You can run this in your browser's inspector console and then save your wiki with <kbd>Ctrl</kbd> or <kbd>Command</kbd> + <kbd>S</kbd> to make it permanent. The new file will be missing the "Settings," "New Page," and "Save" buttons in addition to the "Edit" button on every page.

An additional benefit of removing these buttons is that it reduces the final size of your HTML file a little bit more. You can go one step further and remove no longer needed **siteleteer** code like the `add()`, `del()`, and `edit()` functions, but that will prevent you from making any new pages ever again. If you keep them in the code, you will still be able to use your browser's inspector to manage your site in case you need to make edits.

## Minify the File

**siteleteer** is already quite small, but it can absolutely be smaller. The official HTML is not minified for the purpose of remaining easily hackable by anyone who wants to dig into the code, so running the HTML through a minifier to remove extra spaces and comments will immediately make HTML much smaller!

For example, using one minifier online brought version 1.0.0 of the **siteleteer** core down from about 19 to only 13 kilobytes! Using it on your site's HTML in addition to just the **siteleteer** code will help keep your final HTML size as small as possible, making your site display practically instantaneously.

## Add Offline Mode

This is optional and actually adds extra code for your users to download, but the benefit is that after they visit your site once, they'll be able to access a copy of the data on the site for as long as their browser cache doesn't get cleared even if they don't have internet access or your server goes down.

You can very easily add a script called [UpUp]( and have your offline site available with hardly any work! Download <a href="">`` from the GitHub Repo</a>, extract the files, and put the `upup.min.js` & `upup.sw.min.js` files in the same directory as your **siteleteer** file on your server. Then in the HTML, just add this script tag before the closing body tag:

<script src="upup.min.js"></script>
  'content-url': 'index.html',

Replace `index.html` with the actual name of your **siteleteer** file if it's different. If you have other files, you can include those in the offline cache by including their paths in an `assets` key like so:

  'content-url': 'index.html',
  assets: ['img/logo.png', 'css/style.css', 'headlines.json'],

It's important to note that UpUp will only work if you are serving the files from a URL served over HTTPS, so this will only be useful if you're publishing on an actual domain with an SSL certificate.

Upgrade Guide

Upgrading siteleteer is admittedly not a streamlined process. If you haven't made any changes to the base siteleteer file, follow these steps to upgrade from a previous version:

1. Open your old file in a text editor
2. Find and copy everything after `<main>` up until you reach `</main>` (this is your content)
3. Download the <a href="" download>newest siteleteer file</a>
4. Open the new file in a text editor and find the `<main></main>` line
5. Paste your content between the > and the < on the `<main></main>` line in the new file
6. Save your file and open it in your web browser to make sure it looks right.
7. Marvel at your upgraded siteleteer

If you've changed the CSS at all, you will also need to copy that from the old file into the new one.

If you have altered your siteleteer's Javascript or HTML structure at all, you will need to take a look at the changes to the source code and make the changes manually. Below is a list of each change and the associated Git commits that show exactly what was changed from the prior version.

- 2024-06-14
	- [Commit 1](
	- [Commit 2](
- [2024-03-27](