Removed random comments and replaced em-dashes with hyphens.

This commit is contained in:
sarah committed 2026-09-21 17:37:12 +02:00
1 parent 6083e00504
commit ee7e163837
24 files changed
+198 -363

No files matched your search

+191 -102
View File
@@ -1,54 +1,104 @@
# SaraView
A self-hosted web file previewer/editor — Obsidian's look, without the parts
A self-hosted web file previewer/editor. Obsidian's look, without the parts
you don't use, plus image and video previewing. Read-only integration with
SaraTag's per-file Book tags is included.
## Project layout
It's made by Sarah, hence the name. :3
```
SaraView/
├── Backend/ FastAPI app (Core, Explorer, Preview, Editor, BookReader, Main)
├── Frontend/ React app (Vite)
├── SaraViewConf.toml Your editable config, mounted into the container
├── Dockerfile
└── docker-compose.yml
```
---
## Configure before deploying
## Usage
Edit `SaraViewConf.toml` at the project root:
SaraView is for people who want an Obsidian-style notes app they host
themselves, people who want to preview and edit files from any browser, and
people who want multiple accounts with their own private directories.
- `[Roots]` — add one entry per top-level folder you want browsable, e.g.
`Notes = "/data/notes"`. The path here is the path *inside the container*;
map it to a real folder via a volume mount in `docker-compose.yml`.
- `[SaraTag]` — set `CoreModulePath` to wherever your SaraTag installation's
`.saratag` folder ends up mounted inside the container. Set `Enabled = false`
if you don't want the Book/tag panel at all.
- `[Storage]` — `DataDirectory` is where Settings.toml and the Themes/ folder
live. Leave this pointing at the `saraview_data` named volume already set
up in `docker-compose.yml` — it's intentionally not one of your `[Roots]`,
so it's unreachable from the file browser no matter what.
Example use-cases:
Then in `docker-compose.yml`:
- Browsing and editing markdown notes from your phone, without installing
anything.
- Add a `volumes:` line for every root you declared, mapping your real
ZimaOS path to the container path used in `SaraViewConf.toml`.
- Mount your SaraTag `.saratag` folder read-only the same way.
- Bind the port to your Tailscale interface's IP rather than `0.0.0.0` if you
want it reachable only over the tailnet (same pattern as your other
tailnet-only services).
- Previewing images and videos that live next to your notes.
## Running it
- Giving a friend or family member their own login, with a directory only
they can see.
```bash
docker compose up --build -d
```
---
## Dependencies
Docker + Docker Compose. That's it for running it.
For local development instead: Python 3.11+, and Node.js + npm.
---
## Installation
Here's a step-by-step tutorial.
1. Clone or download this repository.
2. Edit `SaraViewConf.toml` at the project root. Set your `[Roots]`,
`[SaraTag]`, and `[Storage]` paths. (See Config Info below for what each
field does.)
3. Edit `docker-compose.yml`. Add a `volumes:` line for every root you
declared, mount your SaraTag `.saratag` folder read-only, and bind the
port to your Tailscale interface's IP instead of `0.0.0.0` if you want it
reachable only over the tailnet.
4. Run ```docker compose up --build -d```.
The backend serves the built frontend directly, so the whole app is on one
port (`8420` by default).
## Local development (without Docker)
---
## Config Info
Paths in `SaraViewConf.toml` are resolved as given. Use absolute container
paths when running via Docker (see `docker-compose.yml`), matching whatever
you mount the volumes to.
```toml
[SaraView]
ConfigVersion = 1
ApplicationVersion = "0.1.0-beta"
[Server]
Host = "0.0.0.0"
Port = 8420
[Storage]
DataDirectory = "/data/SaraViewData"
[Roots]
Notes = "/data/notes"
[SaraTag]
Enabled = true
CoreModulePath = "/data/SaraTag/.saratag"
HideInternalFiles = true
InternalPatterns = [".saratag", ".SaraTag*", "*.book.toml"]
```
- `[Storage] DataDirectory` is where SaraView keeps its own data - Settings,
Users, Themes, and so on. This is NOT one of the `[Roots]` below, so it's
structurally unreachable from the file browser regardless of any
hidden-file setting. Give it its own persistent volume (see
`docker-compose.yml`) so it survives rebuilds.
- `[Roots]` lists the named roots the browser can navigate. Add as many as
you like; each becomes a top-level entry point in the frontend's root
switcher.
- `[SaraTag]`, if `Enabled`, makes SaraView import SaraTag's own `Core.py`
directly (by file path, not by installing it as a package) to resolve
Book tag files exactly the way SaraTag itself does. This is read-only -
SaraView never writes Book or Lexicon files.
---
## Local Development
Backend:
@@ -58,7 +108,7 @@ pip install -r requirements.txt
uvicorn Main:Application --reload --port 8420
```
Frontend (in a second terminal — Vite proxies `/api` to the backend):
Frontend, in a second terminal. Vite proxies `/api` to the backend.
```bash
cd Frontend
@@ -66,112 +116,151 @@ npm install
npm run dev
```
## Notes on the SaraTag integration
---
SaraView never writes to Book or Lexicon files — it only reads them, by
## Directories as Files
Every directory gets its own note file. It's a hidden `.sv_{DirectoryName}.md`,
created automatically the moment you make the directory. Any extension works
if you rename the note later; markdown is just the default.
Click a directory the same way you'd click a file, and its note opens with
the same edit/view/save toolbar. There's no separate "directory mode."
Renaming or moving a directory keeps its note's name in sync automatically.
Deleting a directory takes its note with it.
Browsing what's actually inside a directory is a sidebar-only action.
Expand a folder there to see its contents. The "Open directory file on
click" setting in Settings decides whether expanding a directory in the
sidebar also opens its note in the main pane, or leaves the main pane alone.
Note files are hidden from listings by default, since their name starts
with `.sv_`. This is independent of the regular "show hidden directories"
setting. Flip on "Show directory note files (.sv_*)" in Settings if you
want to see and manage them directly, like any other file.
---
## SaraTag Integration
SaraView never writes to Book or Lexicon files. It only reads them, by
loading SaraTag's own `Core.py` directly (by file path, not as an installed
package) so tag resolution always matches what SaraTag itself would show.
Editing tags from SaraView isn't implemented yet; SaraTag's own TUI remains
package), so tag resolution always matches what SaraTag itself would show.
Editing tags from SaraView isn't implemented yet. SaraTag's own TUI remains
the place to do that for now.
## Settings and themes
---
Settings (font, font size, active theme, hidden-folder visibility, breadcrumb
visibility) and themes live in `Settings.toml` and `Themes/*.toml` inside the
`saraview_data` volume — not in any of your `[Roots]`, so they're never
browsable from the app itself. Three themes ship built in: CatppuccinMocha,
Gruvbox, and Forest. Every theme is just a flat set of named color roles
(Background, Surface, Text, Red, Orange, ... Purple), so creating a custom
theme from Settings — or hand-writing a new file in `Themes/` — only needs
those same role names filled in.
## Settings and Themes
This is all per-user now — each account gets its own `Settings/<Username>.toml`
Settings (font, font size, active theme, hidden-folder visibility,
breadcrumb visibility) and themes live in `Settings.toml` and
`Themes/*.toml` inside the `saraview_data` volume. Not in any of your
`[Roots]`, so they're never browsable from the app itself.
Three themes ship built in: CatppuccinMocha, Gruvbox, and Forest. Every
theme is just a flat set of named color roles (Background, Surface, Text,
Red, Orange, ... Purple), so creating a custom theme from Settings, or
hand-writing a new file in `Themes/`, only needs those same role names
filled in.
This is all per-user. Each account gets its own `Settings/<Username>.toml`
inside the data volume, seeded from the same defaults the first time that
user logs in. Themes themselves are shared across everyone (there's only one
copy of each theme file), but which theme is active is a per-user choice.
user logs in. Themes themselves are shared across everyone (there's only
one copy of each theme file), but which theme is active is a per-user
choice.
## Accounts and login
---
On first launch, with no accounts yet, SaraView shows a one-time "create the
admin account" screen instead of a normal login — whoever sets that up first
becomes an admin. After that, it's a normal username/password login screen
for everyone.
## Accounts and Login
Accounts live in `Users.toml` in the same `saraview_data` volume as Settings
and Themes (passwords are hashed with PBKDF2-SHA256, never stored in plain
text). Admins get a "Users" section inside Settings to create additional
accounts, including other admins.
On first launch, with no accounts yet, SaraView shows a one-time "create
the admin account" screen instead of a normal login. Whoever sets that up
first becomes an admin. After that, it's a normal username/password login
screen for everyone.
Sessions are currently in-memory only — restarting the container logs
everyone out. Fine for now with a small, trusted set of tailnet users; worth
revisiting if that stops being true.
Accounts live in `Users.toml` in the same `saraview_data` volume as
Settings and Themes. Passwords are hashed with PBKDF2-SHA256, never stored
in plain text. Admins get a "Users" section inside Settings to create
additional accounts, including other admins.
## Running on ZimaOS without building locally
Sessions are currently in-memory only, so restarting the container logs
everyone out. Fine for now with a small, trusted set of tailnet users.
---
## Running on ZimaOS Without Building Locally
The repo publishes a built image to GitHub Container Registry via
`.github/workflows/docker-publish.yml`, so ZimaOS (or any other machine) can
just pull and run it instead of building from source every time.
`.github/workflows/docker-publish.yml`, so ZimaOS (or any other machine)
can just pull and run it instead of building from source every time.
**One-time setup after this workflow first runs:** GHCR packages built by a
workflow's built-in token default to **private**, even on a public repo. Go
to your GitHub profile → Packages → `saraview` → Package settings → Change
visibility → Public. Until you do this, pulling the image from ZimaOS will
fail with an authentication error.
workflow's built-in token default to **private**, even on a public repo.
Go to your GitHub profile → Packages → `saraview` → Package settings →
Change visibility → Public. Until you do this, pulling the image from
ZimaOS will fail with an authentication error.
**Installing on ZimaOS:**
Here's a step-by-step tutorial for installing on ZimaOS.
1. Copy `docker-compose.ghcr.yml` and `SaraViewConf.toml` to the ZimaOS box
(or wherever you're running `docker compose` from for this).
2. Edit the volume paths in `docker-compose.ghcr.yml` the same way you would
for local `docker-compose.yml` — real paths on the left of each `:`.
2. Edit the volume paths in `docker-compose.ghcr.yml` the same way you
would for local `docker-compose.yml`. Real paths on the left of each `:`.
3. In ZimaOS's dashboard, use **Install a customized app** (its Docker
Compose import option) and point it at that compose file — or just run
`docker compose -f docker-compose.ghcr.yml up -d` directly if you'd
Compose import option) and point it at that compose file. Or just run
```docker compose -f docker-compose.ghcr.yml up -d``` directly if you'd
rather do it from a terminal on the box.
**Updating later:** push to `main` (or tag a release like `v1.1.0`) to build
a fresh image, then on ZimaOS re-pull and recreate the container — either
through its UI's update/recreate action, or `docker compose -f
docker-compose.ghcr.yml pull && docker compose -f docker-compose.ghcr.yml up -d`.
**Updating later:** push to `main` (or tag a release like `v1.1.0`) to
build a fresh image, then on ZimaOS re-pull and recreate the container.
Either through its UI's update/recreate action, or:
This gets SaraView pullable as a plain image; it doesn't yet show up with its
own icon/entry in ZimaOS's app store the way bundled apps do — that would
need a CasaOS-format AppStore manifest (icon, category, metadata) submitted
separately, which is a reasonable next step if you want it to feel fully
native rather than "a compose file I pasted in."
```bash
docker compose -f docker-compose.ghcr.yml pull
docker compose -f docker-compose.ghcr.yml up -d
```
## Groups and access control
---
Admin isn't a hardcoded flag — it's the built-in "Admin" group, which can't
## Groups and Access Control
Admin isn't a hardcoded flag. It's the built-in "Admin" group, which can't
be deleted but is otherwise just a group like any other. Manage groups
(create, delete, edit membership) from Settings → Groups (admin-only).
Setting access on a file or directory is **not** admin-only — anyone can
Setting access on a file or directory is **not** admin-only. Anyone can
restrict a file or directory to specific users and/or groups, whether at
creation time (the New File/New Directory dialog includes a search-and-
checkbox picker) or afterwards via the 🔒 button next to any entry, in
either the sidebar tree or the directory-browse pane. If you can currently
see something, you're trusted to change who else can. Admins do not bypass
restrictions - Admin is a management group (creating users, managing groups,
and so on), not a way to view everyone's private directories. Only direct
access to the server's files can see everything.
see something, you're trusted to change who else can.
Restricting is per-file-or-directory — locking a directory covers everything
inside it automatically (there's only ever one restriction record per locked
directory; reaching anything underneath still requires being permitted on
that ancestor), while locking an individual file affects only that file.
Admins do not bypass restrictions. Admin is a management group (creating
users, managing groups, and so on), not a way to view everyone's private
directories. Only direct access to the server's files can see everything.
Restricting is per-file-or-directory. Locking a directory covers everything
inside it automatically (there's only ever one restriction record per
locked directory; reaching anything underneath still requires being
permitted on that ancestor), while locking an individual file affects only
that file.
Anyone without access gets a plain 404, both for direct requests and for
that entry showing up in a directory listing — a restricted item's existence
that entry showing up in a directory listing. A restricted item's existence
isn't revealed to people who can't see it. Admins get a global overview of
every current restriction from Settings → Locked Directories.
## Blame privacy
---
## Blame Privacy
Each person can turn off "Show my edits in others' blame view" in their own
Settings. When that's off, other users still see that lines were changed —
Settings. When that's off, other users still see that lines were changed,
just with the identity redacted, rather than attributing it to someone who
asked not to be shown. You can always see your own attribution regardless of
this setting. There's also a per-viewer toggle for showing avatars instead
of usernames in the blame gutter, using each author's chosen colour either
way.
asked not to be shown. You can always see your own attribution regardless
of this setting.
There's also a per-viewer toggle for showing avatars instead of usernames
in the blame gutter, using each author's chosen colour either way.