We're thrilled you decided to look at our GitHub repository. If you're interested in running and contributing to zSnout, here are some instructions.
To download zSnout, clone it via Git.
git clone https://github.com/zSnout/zSnout.com.git
Once you've downloaded the project, install the dependencies using
npm i
If you want to be absolutely sure that the project runs correctly, use
npm ci
By using ci
, your zSnout installation will use the package versions from
package-lock.json
instead of package.json
.
If you've downloaded the dependencies, you can use a variety of commands to run zSnout locally.
To start a development server, run
npm run dev
Unfortunately, some of the Vue features zSnout uses don't have support with Vite's hot reloading, so you may need to reload your browser window if you're editing the project on the fly.
You can build the project into a dist
directory using
npm run build
You can preview a built project by running
npm run preview
The final URLs of pages should be lowercase and dash-separated. Because their
names are their URLs, files and folders in the public
folder should adhere to
this syntax.
Files and folders in the src
folder should use camelCase. If they are Vue
components, they should begin with an uppercase letter. zSnout has a page
titling system and path assigner system that assumes views are using this
syntax.
All utilities should go in the src/composables
folder, even if they do not
accept refs. However, utilities tightly coupled with their components may stay
in the src/components
folder.
To create a new page, add a new Vue file to src/views
. If you want it to be
the index for a folder, name it folder/index.vue
.
The system that assigns page titles and paths bases them on a page's file name, so make sure to use a short yet descriptive file name.
If a page has an associated cover image, it should be a square 320x320 WebP
image and be placed in the public/images
directory. The file path of the image
should match the output URL of the original path. If the page is an index, the
image should be named folder/index.webp
.
Almost every page starts with a display mode. Displays add the navigation bar and create a consistent layout across all pages. Currently, there are three different display modes. Each mode has its pros and cons, and there are different use cases for each of them. Additionally, each display mode has additional features such as an indicator, help screen, and options menu.
The first display mode is DocumentDisplay. DocumentDisplay is for pages that primarily have text with no background features. Two good examples of this are the Same Number Generator and the Trope Highlighter. Both of these pages have a maximum width of 1000 pixels and have no background elements that take up the entire page. This is also a good display mode for blog articles, as it adds padding on all edges and allows easy scrolling through a document. In fact, Markdown files automatically use this display mode. Additionally, DocumentDisplay handles rounded corners on certain mobile devices, making sure that your document looks good on all of them.
For those who feel constrained by DocumentDisplay's short width, you may pass
the max-width
prop to its Vue component. This remove the 1000 pixel width
constraint, but keeps padding on all edges. The
Storymatic editors use this combined
with a custom 1200 pixel width to allow more space for coding.
The second display mode is FullscreenDisplay. This is primarily combined with an HTML5 canvas. FullscreenDisplay uses a floating navigation bar instead of a sticky one, and the bar doesn't have a background. FullscreenDisplay provides no padding or margins and may extend its contents in a device's rounded edges, if you're using an iPhone or another device with these corners. A good example of FullscreenDisplay is the Fractal Explorer.
The third display mode is MultiPageDisplay. This is meant for layouts with
multiple sections where each section has unique background elements. It also
supports using CSS Scroll Snap to snap between different sections when its Vue
component is passed a snap
property. MultiPageDisplay has a sticky navigation
bar and a footer at the bottom of the page.
On a MultiPageDisplay, you must include Pages as children. Each Page takes up the size of the screen minus the navigation bar automatically. A page alone provides no padding or margins from the edge of the screen or nearby Pages. However, you may use a PageContent component to create the same effect that a DocumentDisplay has by default. A good example of MultiPageDisplay is the Homepage page.
In development mode, a Socket.io server is automatically created on the same port as the main Vite server, and no setup is needed.
When the project is built, the dist
directory will contain a file called
server.mjs
. It is your responsibility to load this as an ES module and call
its .start()
method. This will create a Socket.io server on localhost on port
process.env.PORT || 3000
. You must serve static files normally and forward
Socket.io connections to this server.
If you do not create a Socket.io server and forward requests properly, zSnout will still work properly. However, accounts, cloud bookmarks, and other server features will not work.
If you're using a Socket.io server, you should also add a database. This enables account log in, cloud bookmarks, and other features.
To do this, create a MongoDB database called zsnout
and get a connection URL
similar to this one:
mongodb+srv://<username>:<password>@<name>.<code>.mongodb.net/?retryWrites=true&w=majority
Then set an environment variable in your shell called ZSNOUT_DATABASE
to the
URL.
The database will be populated by collections specified in the Database
interface in
server/database.ts.
In addition to a database, a mail system is also required to create accounts. To do this, get your mail host, port, username, and password, and stuff these into the following environment variables:
ZSNOUT_MAIL_HOST
ZSNOUT_MAIL_PORT
ZSNOUT_MAIL_USER
ZSNOUT_MAIL_PASSWORD
You should also specify the email you are sending from with ZSNOUT_MAIL_FROM
.
zSnout uses Nodemailer to send emails. It will attempt a secure connection to your email server if the specified port is 465.
- Background images
- Page content
- Sticky regions
- Desktop aside
- Page footer
- Indicator
- Notification
- Mobile aside
- Bookmark window
- Navigation bar
- Modal windows and context menus
Any display with a width of at most 400px is considered small
. At this point,
the navigation bar shrinks and DocumentDisplay and PageContent paddings will be
reduced.
A typical DocumentDisplay or PageContent is at most 1000px wide. Displays with
at least this many pixels (wide) are considered medium
.
Any display with a width of at least 1080px is considered large
. Large
displays will show Asides without needing a toggle button.
zSnout automatically compiles .md files into Vue components using
vite-plugin-md
. It automatically adds a sidebar with links to headings to any
Markdown component. You can add [notoc]
to the top of a file to disable this
behavior. You may also add [toc]
to add a table of contents within the main
document instead of in a sidebar. You may use both [notoc]
and [toc]
within
a document to include the inline TOC instead of the sidebar.
Sometimes unsafe code is introduced. When you write unsafe code, prefix it with
/** SAFE */
once you've made it safe. Here are some cases when this happens:
- Using
ObjectId.createFromHexString(string)
is only safe ifstring
is EXACTLY 24 characters long. If it isn't, an error will be thrown, disrupting the server connection. You may only write/** SAFE */
after you've checked thatstring
matches this condition.