mirror of
https://git.srhtnin.garden/sarah/SaraView.git
synced 2026-10-14 18:38:11 +02:00
Removed random comments and replaced em-dashes with hyphens.
This commit is contained in:
1 parent
6083e00504
commit
ee7e163837
24 files changed
+198
-363
No files matched your search
@@ -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.
|
||||
Reference in new issue
Block a user