parent
bb1dbee306
commit
3517c338e5
38 changed files with 1006 additions and 11 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +0,0 @@
|
||||||
book
|
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "themes/abridge"]
|
||||||
|
path = themes/abridge
|
||||||
|
url = https://github.com/jieiku/abridge.git
|
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# docs
|
||||||
|
|
||||||
|
the documentation and main website
|
|
@ -1,6 +0,0 @@
|
||||||
[book]
|
|
||||||
authors = ["tezlm"]
|
|
||||||
language = "en"
|
|
||||||
multilingual = false
|
|
||||||
src = "src"
|
|
||||||
title = "Jackwagon Docs"
|
|
15
config.toml
Normal file
15
config.toml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# The URL the site will be built for
|
||||||
|
base_url = "https://example.com"
|
||||||
|
|
||||||
|
# Whether to automatically compile all Sass files in the sass directory
|
||||||
|
compile_sass = true
|
||||||
|
|
||||||
|
# Whether to build a search index to be used later on by a JavaScript library
|
||||||
|
build_search_index = false
|
||||||
|
|
||||||
|
[markdown]
|
||||||
|
highlight_code = true
|
||||||
|
# highlight_theme = "css"
|
||||||
|
|
||||||
|
[extra]
|
||||||
|
# Put all your custom variables here
|
3
content/docs/_index.md
Normal file
3
content/docs/_index.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
+++
|
||||||
|
page_template = "docs-page.html"
|
||||||
|
+++
|
397
content/docs/api/index.md
Normal file
397
content/docs/api/index.md
Normal file
|
@ -0,0 +1,397 @@
|
||||||
|
+++
|
||||||
|
title = "api"
|
||||||
|
+++
|
||||||
|
|
||||||
|
list of all api paths for client-server api
|
||||||
|
|
||||||
|
each path is versioned on its own
|
||||||
|
|
||||||
|
### endpoint summary
|
||||||
|
|
||||||
|
WARNING: although a good portion of the api is taken by or inspired by
|
||||||
|
matrix, these endpoints aren't the same! Please read this documentation
|
||||||
|
rather than [spec.matrix.org](https://spec.matrix.org).
|
||||||
|
|
||||||
|
NOTE: The api doesn't necessarily follow REST conventions.
|
||||||
|
|
||||||
|
NOTE: This is the PLANNED api, and isn't what is currently
|
||||||
|
implemented. The endpoints and structs may change.
|
||||||
|
|
||||||
|
#### client
|
||||||
|
|
||||||
|
prefix = `/_jackwagon/client`
|
||||||
|
|
||||||
|
The main apis for clients to interact with servers. Authentication will be outsourced to oidc.
|
||||||
|
|
||||||
|
but QUERY isn't widely supported :(
|
||||||
|
|
||||||
|
| method | path | description |
|
||||||
|
|--------|---------------------------------------------------|----------------------------------------------------|
|
||||||
|
| QUERY | /v1/info | Get info about this server |
|
||||||
|
| QUERY | /v1/sync | Receive new events; see [syncing](/docs/syncing) |
|
||||||
|
| QUERY | /v1/threads | Query for threads, get inbox |
|
||||||
|
| PUT | /v1/threads/participation | Set thread participation |
|
||||||
|
| POST | /v1/ack | Mark messages as read |
|
||||||
|
| GET | /v1/users/me | Get info about this user (profile) (whoami) |
|
||||||
|
| GET | /v1/users/{userId} | Get info about a user |
|
||||||
|
| PATCH | /v1/users/me | Set info about this user |
|
||||||
|
| PATCH | /v1/users/{userId} | Set info about a user |
|
||||||
|
| PUT | /v1/account-data/{key} | Write account data |
|
||||||
|
| GET | /v1/account-data/{key} | Read account data |
|
||||||
|
| POST | /v1/rooms/create | Create a room |
|
||||||
|
| PUT | /v1/rooms/membership | Change room membership for yourself and others |
|
||||||
|
| POST | /v1/rooms/{roomId}/send/{eventType} | Send an event |
|
||||||
|
| POST | /v1/rooms/{roomId}/ephemeral/{eventType} | Send an ephemeral event |
|
||||||
|
| PUT | /v1/rooms/{roomId}/state/{eventType}/{stateKey} | Send a state event, mutating the state of a room |
|
||||||
|
| GET | /v1/rooms/{roomId}/state/{eventType?}/{stateKey?} | Read state from a room |
|
||||||
|
| QUERY | /v1/rooms/{roomId}/events | Fetch events |
|
||||||
|
| QUERY | /v1/rooms/{roomId}/relations | Fetch relations |
|
||||||
|
| QUERY | /v1/rooms/{roomId}/aliases | Get aliases |
|
||||||
|
| PUT | /v1/rooms/{roomId}/aliases | Set aliases |
|
||||||
|
| PUT | /v1/rooms/{roomId}/account-data/{key} | Write account data |
|
||||||
|
| GET | /v1/rooms/{roomId}/account-data/{key} | Read account data |
|
||||||
|
| POST | /v1/aliases/resolve | Resolve aliases to room ids |
|
||||||
|
| QUERY | /v1/spaces/{roomId}/hierarchy | Fetch space children |
|
||||||
|
| QUERY | /v1/search/users | Search for users |
|
||||||
|
| QUERY | /v1/search/messages | Search for messages |
|
||||||
|
| QUERY | /v1/search/threads | Search for threads |
|
||||||
|
| QUERY | /v1/search/rooms | Search for rooms |
|
||||||
|
| ????? | /v1/voip/???? | Anything needed for voip |
|
||||||
|
| POST | /v1/send-to-device | Send a message directly to a device |
|
||||||
|
| POST | /v1/keys/upload | Upload/publish encryption keys |
|
||||||
|
| POST | /v1/keys/upload-cross-keys | Upload/publish cross-signing encryption keys |
|
||||||
|
| POST | /v1/keys/upload-cross-sigs | Upload/publish cross-signing encryption signatures |
|
||||||
|
| POST | /v1/keys/query | Get another user's encryption keys |
|
||||||
|
| POST | /v1/keys/claim | Claim another user's encryption keys |
|
||||||
|
| PATCH | /v1/key-backup | Add/remove keys from the key backup |
|
||||||
|
| QUERY | /v1/key-backup | Retrieve keys from the key backup |
|
||||||
|
| GET | /v1/key-backup/version | Get the latest version |
|
||||||
|
| POST | /v1/key-backup/version | Create a new version |
|
||||||
|
| GET | /v1/key-backup/version/{version} | Get a version |
|
||||||
|
| PUT | /v1/key-backup/version/{version} | Update a version |
|
||||||
|
| DELETE | /v1/key-backup/version/{version} | Delete a version |
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// post /v1/rooms/threads
|
||||||
|
struct GetThreads {
|
||||||
|
room_ids: Array<RoomId>,
|
||||||
|
from: Option<string>,
|
||||||
|
filter: Option<ThreadFilter>,
|
||||||
|
sort: Option<ThreadSort>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ThreadFilter {
|
||||||
|
/// add muted threads
|
||||||
|
muted: bool,
|
||||||
|
|
||||||
|
/// remove unwatched threads
|
||||||
|
watching: bool,
|
||||||
|
|
||||||
|
/// remove read threads
|
||||||
|
unread: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ThreadSort {
|
||||||
|
/// Newest posts first.
|
||||||
|
#[default]
|
||||||
|
New,
|
||||||
|
|
||||||
|
/// Oldest posts first. Only used for inbox.
|
||||||
|
Old,
|
||||||
|
|
||||||
|
/// Sort by the number of +1s (in a time frame)
|
||||||
|
Votes(Option<Date>),
|
||||||
|
|
||||||
|
/// Sort by the number of replies/comments (in a time frame)
|
||||||
|
Comments(Option<Date>),
|
||||||
|
|
||||||
|
/// Sort by the last reply/comment timestamp
|
||||||
|
Activity,
|
||||||
|
|
||||||
|
/// Sort by the "hot algorithm". By far the most complex. Meant for inbox and large communities.
|
||||||
|
Hot,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
post /v1/rooms/membership
|
||||||
|
{
|
||||||
|
rooms: Array<{
|
||||||
|
room: RoomId | RoomAlias,
|
||||||
|
user_id?: UserId,
|
||||||
|
membership?: "join" | "leave" | "invite" | "knock" | "ban",
|
||||||
|
forget?: boolean, // standalone or when membership = leave?
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
|
||||||
|
/events
|
||||||
|
{
|
||||||
|
event_id?: EventId,
|
||||||
|
limit_before?: number,
|
||||||
|
limit_after?: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
/relations
|
||||||
|
{
|
||||||
|
event_id: EventId,
|
||||||
|
rel_type?: string,
|
||||||
|
event_types?: Array<string>,
|
||||||
|
depth?: number, // recursion depth?
|
||||||
|
|
||||||
|
// pagination
|
||||||
|
limit?: number,
|
||||||
|
after?: string,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
/// The standard "text" type. Used for all user-facing text.
|
||||||
|
struct Text(Vec<TextBlock>);
|
||||||
|
|
||||||
|
struct TextBlock {
|
||||||
|
/// The content itself.
|
||||||
|
// NOTE: should this be `any` instead of string?
|
||||||
|
body: String,
|
||||||
|
|
||||||
|
/// The language of the text (ie. en, en_US, i forget the name for this convention)
|
||||||
|
lang: Option<String>,
|
||||||
|
|
||||||
|
/// The mime type of the body. May be `text/plain` or `text/html`
|
||||||
|
// NOTE: maybe should it be `text/jackwagon+html` or `text/html+jackwagon`?
|
||||||
|
type: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
this: "is an example object",
|
||||||
|
text1: [{ body: "the most basic text block"}],
|
||||||
|
text2: [
|
||||||
|
{ body: "now with *formatting*" },
|
||||||
|
{ body: "now with <em>formatting</em>", type: "text/html" },
|
||||||
|
],
|
||||||
|
text3: [
|
||||||
|
{ body: "this may not be exposed in ui, but localization can exist (mostly for bots?)" },
|
||||||
|
{ body: "(pretend i can speak another language)", lang: "another_LANG" },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
#### federation
|
||||||
|
|
||||||
|
prefix = `/_jackwagon/federation`
|
||||||
|
|
||||||
|
This is how servers federate with each other.
|
||||||
|
|
||||||
|
| method | path | description |
|
||||||
|
|--------|------ |------ |
|
||||||
|
| QUERY | /v1/info | Get public info about this server |
|
||||||
|
| POST | /v1/send | Send new events (PDUs) |
|
||||||
|
| POST | /v1/make-join | Ask a server to create a join event, since ours doesn't have room state yet |
|
||||||
|
| POST | /v1/make-invite | Same as above for inviting other users |
|
||||||
|
| POST | /v1/make-leave | Same as above for leave (rejecting invites, specifically) |
|
||||||
|
| POST | /v1/make-knock | Same as above for knock |
|
||||||
|
| POST | /v1/send-join | Send the join |
|
||||||
|
| POST | /v1/send-invite | Send the invite |
|
||||||
|
| POST | /v1/send-leave | Send the leave |
|
||||||
|
| POST | /v1/send-knock | Send the knock |
|
||||||
|
| GET | /v1/state/{roomId}/{eventId} | Get a snapshot of room state at a specific event id |
|
||||||
|
| GET | /v1/state-ids/{roomId}/{eventId} | Like /state, but only the ids instead of full events |
|
||||||
|
| GET | /v1/event/{roomId}/{eventId} | Get an event |
|
||||||
|
| GET | /v1/event-auth/{roomId}/{eventId} | Get the full auth chain of an event |
|
||||||
|
| POST | /v1/backfill/{roomId} | Fetch a range of history |
|
||||||
|
| POST | /v1/get-missing-events/{roomId} | Fetch some specific events |
|
||||||
|
| POST | /v1/keys/server | Fetch the server's signing key |
|
||||||
|
| POST | /v1/keys/query | Ask the server for another server's signing key |
|
||||||
|
| GET | /v1/hierarchy/{roomId} | Get a space's hierarchy |
|
||||||
|
| GET | /v1/query/alias/{roomAlias} | Resolve a room alias |
|
||||||
|
| GET | /v1/query/user/{userId} | Get a user's profile |
|
||||||
|
| GET | /v1/query/devices/{userId} | Get a user's devices |
|
||||||
|
|
||||||
|
#### media
|
||||||
|
|
||||||
|
prefix = `/_jackwagon/media`
|
||||||
|
|
||||||
|
Specifically for media, which is transferred out of band. I really want
|
||||||
|
to rework the `blobs` api, since I know it's possible to decentralize
|
||||||
|
media but still allow streaming it with pubkeys...
|
||||||
|
|
||||||
|
| method | path | description |
|
||||||
|
|--------|------ |------------- |
|
||||||
|
| POST | /v1/blobs | Upload a blob |
|
||||||
|
| GET | /v1/blobs/:id | Download a blob |
|
||||||
|
| DELETE | /v1/blobs/:id | Delete a blob (only uploader and admins can use) |
|
||||||
|
| GET | /v1/blobs/:id/thumbnail | Download a blob's server generate thumbnail |
|
||||||
|
| POST | /v1/url | Generate a url preview |
|
||||||
|
|
||||||
|
#### appservice
|
||||||
|
|
||||||
|
prefix = `/_jackwagon/appservice`
|
||||||
|
|
||||||
|
APIs for appservices. Notably, this api exists *on the appservice*,
|
||||||
|
not the homeserver and is used for the homeserver to communicate to
|
||||||
|
the appservice.
|
||||||
|
|
||||||
|
Appservices can pass `?user_id` on any client-server api endpoint to
|
||||||
|
masquerade as that user. They can also use `?timestamp` to set a custom
|
||||||
|
origin_server_ts when sending events (though it doesn't rewrite the dag!).
|
||||||
|
|
||||||
|
| method | path | description |
|
||||||
|
|--------|--------------------------|--------------------------------------------|
|
||||||
|
| GET | /v1/health | A health check for the application service |
|
||||||
|
| PUT | /v1/transactions/{txnId} | Receive some events |
|
||||||
|
| GET | /v1/users/{userId} | Get or create a user's profile |
|
||||||
|
| GET | /v1/aliases/{roomAlias} | Get or create a room |
|
||||||
|
|
||||||
|
#### admin
|
||||||
|
|
||||||
|
prefix = `/_jackwagon/admin`
|
||||||
|
|
||||||
|
APIs for administrating a server.
|
||||||
|
|
||||||
|
| method | path | description |
|
||||||
|
|--------|-------------------------------------|-----------------------------------------------------|
|
||||||
|
| GET | /v1/stats | Get statistics of the server |
|
||||||
|
| GET | /v1/appservices | Get a list of appservices |
|
||||||
|
| PUT | /v1/appservices/:id | Register or update an appservice |
|
||||||
|
| GET | /v1/appservices/:id | Get an appservice's config |
|
||||||
|
| DELETE | /v1/appservices/:id | Delete an appservice |
|
||||||
|
| GET | /v1/users | Get a list of all known (or only ?local=true) users |
|
||||||
|
| GET | /v1/users/{userId} | Get a user |
|
||||||
|
| PUT | /v1/users/{userId} | Update a user |
|
||||||
|
| GET | /v1/rooms | Get a list of rooms |
|
||||||
|
| GET | /v1/rooms/{roomId} | Get a room |
|
||||||
|
| PUT | /v1/rooms/{roomId} | Update a room |
|
||||||
|
| POST | /v1/send-notice | Send a server notice |
|
||||||
|
| POST | /v1/debug/get-pdu/{eventId} | Get a pdu |
|
||||||
|
| POST | /v1/debug/get-auth/{eventId} | Get a pdu's auth chain |
|
||||||
|
| POST | /v1/debug/get-extremities/{eventId} | Get a pdu's forward extremities |
|
||||||
|
| POST | /v1/debug/sign | Sign json |
|
||||||
|
| POST | /v1/debug/verify | Verify a pdu |
|
||||||
|
|
||||||
|
this should probably be migrated out of REST for bulk deactivation
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type AppserviceConfig = {
|
||||||
|
description: string, // a human readable description
|
||||||
|
as_token: string, // secret token the appservice uses to authenticate itself
|
||||||
|
hs_token: string, // secret token the homeserver uses to authenticate itself
|
||||||
|
url: string, // the url the homeserver uses to communicate with the appservice
|
||||||
|
media: string, // the url the homeserver uses to communicate with the appservice
|
||||||
|
namespaces: {
|
||||||
|
users?: Array<{ regex: string }>,
|
||||||
|
aliases?: Array<{ regex: string }>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// quarantined users cannot dm people among other restrictions
|
||||||
|
type UserConfig = {
|
||||||
|
profile: UserProfile,
|
||||||
|
state: "active" | "quarantined" | "readonly" | "disabled",
|
||||||
|
};
|
||||||
|
|
||||||
|
// quarantined rooms cannot be joined by any new users (but existing members can stay), and will not show up in /hierarchy
|
||||||
|
// exiled rooms cannot be interacted with at all, and any joined users will leave. the server may purge the state.
|
||||||
|
type RoomConfig = {
|
||||||
|
state: "active" | "quarantined" | "exiled",
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### primitives
|
||||||
|
|
||||||
|
| name | format | description |
|
||||||
|
|-|-|-|
|
||||||
|
|room id|!opaque:domain.tld|A globally unique identifier for a room. The domain part is purely to ensure uniqueness, and is meaningless otherwise.|
|
||||||
|
|user id|@name:domain.tld|A globally unique identifier for a user.|
|
||||||
|
|event id|$opaque|A globally unique identifier for an event.|
|
||||||
|
|
||||||
|
### event struct
|
||||||
|
|
||||||
|
| field | type | description |
|
||||||
|
|-|-|-|
|
||||||
|
| event_id | event id | a unique identifier for this event |
|
||||||
|
| room_id? | room id | the room this event originated from* |
|
||||||
|
| content | any | arbitrary content; in practice, this probably matches the event type |
|
||||||
|
| sender | user id | the sender of this event |
|
||||||
|
| state_key? | string | if this is a state event |
|
||||||
|
| type | string | the type of this event |
|
||||||
|
| origin_server_ts | number | the timestamp at the server this event originated from |
|
||||||
|
| unsigned | unsigned data | anything extra the server calculated |
|
||||||
|
|
||||||
|
*only present in some endpoints
|
||||||
|
|
||||||
|
### standard types
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// Text
|
||||||
|
// a string is shorthand for a single TextPart of type text/plain
|
||||||
|
type Text = string | Array<TextPart>;
|
||||||
|
type TextPart = {
|
||||||
|
body: string,
|
||||||
|
lang?: string,
|
||||||
|
type?: "text/plain" | "text/html" | string,
|
||||||
|
};
|
||||||
|
|
||||||
|
type File = {
|
||||||
|
url: /mxc/,
|
||||||
|
info: {
|
||||||
|
alt: Text,
|
||||||
|
type: number, // mime type
|
||||||
|
size: number, // in bytes
|
||||||
|
width?: number, // type = image, video
|
||||||
|
height?: number, // type = image, video
|
||||||
|
duration?: number, // type = audio, video
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Events sent to clients
|
||||||
|
type ClientEvent = {
|
||||||
|
event_id: EventId,
|
||||||
|
room_id?: RoomId, // removed in /sync, since the room id is sent anyway
|
||||||
|
content: any,
|
||||||
|
sender: UserId,
|
||||||
|
state_key?: string,
|
||||||
|
type: string,
|
||||||
|
origin_server_ts: number,
|
||||||
|
unsigned: UnsignedData,
|
||||||
|
};
|
||||||
|
|
||||||
|
type ServerEvent = {
|
||||||
|
auth_events: Array<EventId>,
|
||||||
|
content: any,
|
||||||
|
hashes: any,
|
||||||
|
origin_server_ts: number,
|
||||||
|
prev_events: Array<EventId>,
|
||||||
|
room_id: RoomId,
|
||||||
|
sender: UserId,
|
||||||
|
signatures: any,
|
||||||
|
state_key?: string,
|
||||||
|
type: string,
|
||||||
|
// unsigned: UnsignedData,
|
||||||
|
};
|
||||||
|
|
||||||
|
type UnsignedData = {
|
||||||
|
prev_content?: any,
|
||||||
|
redacted_because?: ClientEvent,
|
||||||
|
transaction_id?: string,
|
||||||
|
relations: {
|
||||||
|
"m.thread": {
|
||||||
|
count: number,
|
||||||
|
participation: "participation",
|
||||||
|
},
|
||||||
|
"m.replace": {
|
||||||
|
latest_event: ClientEvent,
|
||||||
|
},
|
||||||
|
"m.plus": {
|
||||||
|
count: number,
|
||||||
|
},
|
||||||
|
"m.annotation": {
|
||||||
|
annotations: Array<ClientEvent>,
|
||||||
|
count: number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
unreads: Unreads,
|
||||||
|
// per-event account data?
|
||||||
|
// account_data: any,
|
||||||
|
};
|
||||||
|
```
|
15
content/docs/data.md
Normal file
15
content/docs/data.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
+++
|
||||||
|
title = "data"
|
||||||
|
+++
|
||||||
|
|
||||||
|
list of data structures
|
||||||
|
|
||||||
|
## events
|
||||||
|
|
||||||
|
`m.message`
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"m.text": "bar"
|
||||||
|
}
|
||||||
|
```
|
33
content/docs/design.md
Normal file
33
content/docs/design.md
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
+++
|
||||||
|
title = "design"
|
||||||
|
+++
|
||||||
|
|
||||||
|
there are some design choices
|
||||||
|
|
||||||
|
## faq
|
||||||
|
|
||||||
|
### no main instance
|
||||||
|
|
||||||
|
i'm a programmer not a moderator and don't want to deal with that
|
||||||
|
|
||||||
|
yeah it will hurt adoption, but the goal isn't to amass a ton of users
|
||||||
|
|
||||||
|
## ui
|
||||||
|
|
||||||
|
### why thread only
|
||||||
|
|
||||||
|
it strikes a nice balance between async and synchronous.
|
||||||
|
|
||||||
|
i *may* add fully async tree-style reply style rooms.
|
||||||
|
|
||||||
|
fully synchronous chat is not planned.
|
||||||
|
|
||||||
|
## technical
|
||||||
|
|
||||||
|
### the api is not restful
|
||||||
|
|
||||||
|
it uses batching
|
||||||
|
|
||||||
|
### why long polling
|
||||||
|
|
||||||
|
http/3
|
12
content/docs/hello.md
Normal file
12
content/docs/hello.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
+++
|
||||||
|
title = "hello"
|
||||||
|
+++
|
||||||
|
|
||||||
|
welcome to the project, here's documentation
|
||||||
|
|
||||||
|
- user docs for new people
|
||||||
|
- advanced docs for power users, mods/admins
|
||||||
|
- operator docs for running a server
|
||||||
|
- developer docs for developing bots and working with the api
|
||||||
|
- specification
|
||||||
|
- useful links to repos
|
70
content/docs/install.md
Normal file
70
content/docs/install.md
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
+++
|
||||||
|
title = "install"
|
||||||
|
+++
|
||||||
|
|
||||||
|
## docker compose
|
||||||
|
|
||||||
|
it's planned to be modular and composed of multiple parts
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# This is the main jackwagon server
|
||||||
|
backend:
|
||||||
|
# image: matrixconduit/matrix-conduit:latest
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
args:
|
||||||
|
CREATED: '2021-03-16T08:18:27Z'
|
||||||
|
VERSION: '0.1.0'
|
||||||
|
LOCAL: 'false'
|
||||||
|
GIT_REF: origin/master
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 8448:6167
|
||||||
|
volumes:
|
||||||
|
- db:/var/lib/matrix-conduit/
|
||||||
|
environment:
|
||||||
|
CONDUIT_SERVER_NAME: your.server.name # EDIT THIS
|
||||||
|
CONDUIT_DATABASE_PATH: /var/lib/matrix-conduit/
|
||||||
|
CONDUIT_DATABASE_BACKEND: rocksdb
|
||||||
|
CONDUIT_PORT: 6167
|
||||||
|
CONDUIT_MAX_REQUEST_SIZE: 20_000_000 # in bytes, ~20 MB
|
||||||
|
CONDUIT_ALLOW_REGISTRATION: 'true'
|
||||||
|
CONDUIT_ALLOW_FEDERATION: 'true'
|
||||||
|
CONDUIT_ALLOW_CHECK_FOR_UPDATES: 'true'
|
||||||
|
CONDUIT_TRUSTED_SERVERS: '["matrix.org"]'
|
||||||
|
#CONDUIT_MAX_CONCURRENT_REQUESTS: 100
|
||||||
|
#CONDUIT_LOG: warn,rocket=off,_=off,sled=off
|
||||||
|
CONDUIT_ADDRESS: 0.0.0.0
|
||||||
|
CONDUIT_CONFIG: '' # Ignore this
|
||||||
|
|
||||||
|
# the main frontend
|
||||||
|
frontend:
|
||||||
|
image: vectorim/element-web:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 8009:80
|
||||||
|
|
||||||
|
# handle turn/voip, you can also run this on other servers
|
||||||
|
coturn:
|
||||||
|
image: coturn/coturn
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 3478:3478
|
||||||
|
- 3478:3478/udp
|
||||||
|
- 5349:5349
|
||||||
|
- 5349:5349/udp
|
||||||
|
- 49152-65535:49152-65535/udp
|
||||||
|
|
||||||
|
# database
|
||||||
|
postgres:
|
||||||
|
image: postgres
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: example
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db:
|
||||||
|
```
|
70
content/docs/syncing.md
Normal file
70
content/docs/syncing.md
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
+++
|
||||||
|
title = "syncing"
|
||||||
|
+++
|
||||||
|
|
||||||
|
how to sync
|
||||||
|
|
||||||
|
call `POST /v1/sync` (or `QUERY /v1/sync`?) in a loop
|
||||||
|
|
||||||
|
## goals
|
||||||
|
|
||||||
|
1. Be able to incrementally update a local offline copy
|
||||||
|
2. Be able to fetch only what is needed
|
||||||
|
|
||||||
|
- query and update state, threads, members
|
||||||
|
|
||||||
|
todo: write out
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type Query = {
|
||||||
|
state: Array<[string, string]>, // (event_type, state_key)
|
||||||
|
subscribe: boolean,
|
||||||
|
threads: {
|
||||||
|
limit: number,
|
||||||
|
timeline_limit: number,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
type Request = {
|
||||||
|
conn_id: string,
|
||||||
|
pos: string,
|
||||||
|
delta_token: string,
|
||||||
|
|
||||||
|
lists: Record<string, null | {
|
||||||
|
limit: number,
|
||||||
|
filters: {
|
||||||
|
types: Array<string>,
|
||||||
|
purposes: Array<string>,
|
||||||
|
spaces: Array<RoomId>,
|
||||||
|
tombstoned: Array<RoomId>,
|
||||||
|
},
|
||||||
|
} & Query>,
|
||||||
|
|
||||||
|
rooms: Record<RoomId, null | Query>,
|
||||||
|
|
||||||
|
extensions: {
|
||||||
|
presence: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
account_data: {
|
||||||
|
enabled: true,
|
||||||
|
types?: Array<string>,
|
||||||
|
rooms?: Array<RoomId>,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type Reponse = {
|
||||||
|
lists: Record<string, null | {
|
||||||
|
count: number,
|
||||||
|
}>,
|
||||||
|
|
||||||
|
rooms: Record<RoomId, {
|
||||||
|
initial?: true,
|
||||||
|
state: Array<StateEvent>,
|
||||||
|
threads: Array<Event>,
|
||||||
|
timeline: Array<Event>,
|
||||||
|
}>,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
1
public/fonts.css
Normal file
1
public/fonts.css
Normal file
|
@ -0,0 +1 @@
|
||||||
|
@font-face{font-family:"Atkinson Hyperlegible";font-style:normal;font-weight:normal;font-display:swap;src:url(/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Regular.ttf)}@font-face{font-family:"Atkinson Hyperlegible";font-style:normal;font-weight:bold;font-display:swap;src:url(/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Bold.ttf)}@font-face{font-family:"Atkinson Hyperlegible";font-style:italic;font-weight:normal;font-display:swap;src:url(/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Italic.ttf)}@font-face{font-family:"Atkinson Hyperlegible";font-style:italic;font-weight:bold;font-display:swap;src:url(/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-BoldItalic.ttf)}@font-face{font-family:"Iosevka Zesty";font-style:normal;font-weight:normal;font-display:swap;src:url(/fonts/iosevka/iosevka-zesty.ttf)}
|
BIN
public/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Bold.ttf
Normal file
BIN
public/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Bold.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
93
public/fonts/atkinson-hyperlegible/OFL.txt
Normal file
93
public/fonts/atkinson-hyperlegible/OFL.txt
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
Copyright 2020 Braille Institute of America, Inc.
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
BIN
public/fonts/iosevka/iosevka-zesty-bold-extended-italic.ttf
Normal file
BIN
public/fonts/iosevka/iosevka-zesty-bold-extended-italic.ttf
Normal file
Binary file not shown.
BIN
public/fonts/iosevka/iosevka-zesty-bold-extended.ttf
Normal file
BIN
public/fonts/iosevka/iosevka-zesty-bold-extended.ttf
Normal file
Binary file not shown.
BIN
public/fonts/iosevka/iosevka-zesty-bold-italic.ttf
Normal file
BIN
public/fonts/iosevka/iosevka-zesty-bold-italic.ttf
Normal file
Binary file not shown.
BIN
public/fonts/iosevka/iosevka-zesty-bold.ttf
Normal file
BIN
public/fonts/iosevka/iosevka-zesty-bold.ttf
Normal file
Binary file not shown.
BIN
public/fonts/iosevka/iosevka-zesty-extended-italic.ttf
Normal file
BIN
public/fonts/iosevka/iosevka-zesty-extended-italic.ttf
Normal file
Binary file not shown.
BIN
public/fonts/iosevka/iosevka-zesty-extended.ttf
Normal file
BIN
public/fonts/iosevka/iosevka-zesty-extended.ttf
Normal file
Binary file not shown.
BIN
public/fonts/iosevka/iosevka-zesty-italic.ttf
Normal file
BIN
public/fonts/iosevka/iosevka-zesty-italic.ttf
Normal file
Binary file not shown.
BIN
public/fonts/iosevka/iosevka-zesty.ttf
Normal file
BIN
public/fonts/iosevka/iosevka-zesty.ttf
Normal file
Binary file not shown.
BIN
public/psyqui.mp4
Normal file
BIN
public/psyqui.mp4
Normal file
Binary file not shown.
1
public/style.css
Normal file
1
public/style.css
Normal file
|
@ -0,0 +1 @@
|
||||||
|
@font-face{font-family:"Atkinson Hyperlegible";font-style:normal;font-weight:normal;font-display:swap;src:url(/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Regular.ttf)}@font-face{font-family:"Atkinson Hyperlegible";font-style:normal;font-weight:bold;font-display:swap;src:url(/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Bold.ttf)}@font-face{font-family:"Atkinson Hyperlegible";font-style:italic;font-weight:normal;font-display:swap;src:url(/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Italic.ttf)}@font-face{font-family:"Atkinson Hyperlegible";font-style:italic;font-weight:bold;font-display:swap;src:url(/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-BoldItalic.ttf)}@font-face{font-family:"Iosevka Zesty";font-style:normal;font-weight:normal;font-display:swap;src:url(/fonts/iosevka/iosevka-zesty.ttf)}:root{font:16px/1.5 "Atkinson Hyperlegible",Inter,system-ui,Avenir,Helvetica,Arial,sans-serif;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--background-1: #24262b;--background-2: #1e2024;--background-3: #191b1d;--background-4: #17181a;--foreground-1: #eae8efdd;--foreground-2: #eae8efb4}*{box-sizing:border-box;margin:0;padding:0}body{background:var(--background-1);color:var(--foreground-1);margin:0}section,main{padding:2rem max(50vw - 350px,16px)}#blurb{width:50%;padding:2rem;padding-left:max(50vw - 350px,16px);background:var(--background-2)}#blurb>h1{text-shadow:1px 1px #822eba,2px 2px rgba(130,46,186,.8),3px 3px rgba(130,46,186,.6),4px 4px rgba(130,46,186,.4),5px 5px rgba(130,46,186,.2);margin-bottom:2rem}#blurb a{padding:8px 16px;background:#555;color:var(--foreground-1);text-decoration:none;border-radius:2px;cursor:pointer}#video{display:flex;gap:1rem;overflow-x:auto;margin-left:40%;width:60%;height:350px;padding:2rem;background:var(--background-3)}#video>video{height:100%}a{color:#bd7aea}#about{display:flex;gap:16px}#about>div{flex:1}ol,ul{padding-left:1rem}@media (max-width: 750px){#blurb,#video{width:100%;padding:2rem;margin-left:0}#about{flex-direction:column}}svg{position:fixed;bottom:0}pre{padding:4px;border-radius:4px;background:var(--background-3);overflow-x:auto}#line{animation:move 999999s}@keyframes move{from{stroke-dashoffset:0}to{stroke-dashoffset:10000000}}nav{display:flex;flex-direction:column;float:left;width:256px;padding:8px;background:var(--background-2)}table{border:solid var(--background-3) 1px;width:100%;border-collapse:collapse}table tr{background:var(--background-2)}table tr:nth-child(even){background:var(--background-3)}table thead tr{background:var(--background-4)}table td,table th{padding:4px;text-align:left}
|
39
sass/fonts.scss
Normal file
39
sass/fonts.scss
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
@font-face {
|
||||||
|
font-family: "Atkinson Hyperlegible";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Regular.ttf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Atkinson Hyperlegible";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: bold;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Bold.ttf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Atkinson Hyperlegible";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: normal;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Italic.ttf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Atkinson Hyperlegible";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: bold;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(/fonts/atkinson-hyperlegible/AtkinsonHyperlegible-BoldItalic.ttf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Iosevka Zesty";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(/fonts/iosevka/iosevka-zesty.ttf);
|
||||||
|
}
|
155
sass/style.scss
Normal file
155
sass/style.scss
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
@import "./fonts.scss";
|
||||||
|
|
||||||
|
:root {
|
||||||
|
font: 16px/1.5 "Atkinson Hyperlegible", Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
font-synthesis: none;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
--background-1: #24262b;
|
||||||
|
--background-2: #1e2024;
|
||||||
|
--background-3: #191b1d;
|
||||||
|
--background-4: #17181a;
|
||||||
|
--foreground-1: #eae8efdd;
|
||||||
|
--foreground-2: #eae8efb4;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: var(--background-1);
|
||||||
|
color: var(--foreground-1);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
section, main {
|
||||||
|
padding: 2rem max(calc(50vw - 350px), 16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#blurb {
|
||||||
|
width: 50%;
|
||||||
|
padding: 2rem;
|
||||||
|
padding-left: max(calc(50vw - 350px), 16px);
|
||||||
|
background: var(--background-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#blurb > h1 {
|
||||||
|
text-shadow:
|
||||||
|
1px 1px #822ebaff,
|
||||||
|
2px 2px #822ebacc,
|
||||||
|
3px 3px #822eba99,
|
||||||
|
4px 4px #822eba66,
|
||||||
|
5px 5px #822eba33;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#blurb a {
|
||||||
|
padding: 8px 16px;
|
||||||
|
background: #555;
|
||||||
|
color: var(--foreground-1);
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#video {
|
||||||
|
display: flex;
|
||||||
|
gap: 1rem;
|
||||||
|
overflow-x: auto;
|
||||||
|
margin-left: 40%;
|
||||||
|
width: 60%;
|
||||||
|
height: 350px;
|
||||||
|
padding: 2rem;
|
||||||
|
background: var(--background-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#video > video {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #bd7aea;
|
||||||
|
}
|
||||||
|
|
||||||
|
#about {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#about > div {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol, ul {
|
||||||
|
padding-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 750px) {
|
||||||
|
#blurb, #video {
|
||||||
|
width: 100%;
|
||||||
|
padding: 2rem;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#about {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: var(--background-3);
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#line {
|
||||||
|
animation: move 999999s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes move {
|
||||||
|
from { stroke-dashoffset: 0; }
|
||||||
|
to { stroke-dashoffset: 10000000; }
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
float: left;
|
||||||
|
width: 256px;
|
||||||
|
padding: 8px;
|
||||||
|
background: var(--background-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border: solid var(--background-3) 1px;
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
|
||||||
|
& tr {
|
||||||
|
background: var(--background-2);
|
||||||
|
|
||||||
|
&:nth-child(even) {
|
||||||
|
background: var(--background-3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& thead tr {
|
||||||
|
background: var(--background-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
& td, th {
|
||||||
|
padding: 4px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
# Summary
|
|
||||||
|
|
||||||
- [Chapter 1](./chapter_1.md)
|
|
|
@ -1 +0,0 @@
|
||||||
# Chapter 1
|
|
1
static/fonts
Symbolic link
1
static/fonts
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../frontend-web/src/assets/fonts/
|
BIN
static/psyqui.mp4
Normal file
BIN
static/psyqui.mp4
Normal file
Binary file not shown.
6
templates/404.html
Normal file
6
templates/404.html
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{% block content %}
|
||||||
|
<main>
|
||||||
|
<h1>404</h1>
|
||||||
|
<p>not found - <a href="/">back to home</a></p>
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
13
templates/base.html
Normal file
13
templates/base.html
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf8" />
|
||||||
|
<title>{% block title %}unnamed{% endblock %}</title>
|
||||||
|
{% block head %}
|
||||||
|
<link rel="stylesheet" href="/style.css" />
|
||||||
|
{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
20
templates/docs-page.html
Normal file
20
templates/docs-page.html
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{{ page.title }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% set section = get_section(path="docs/_index.md") %}
|
||||||
|
|
||||||
|
<nav>
|
||||||
|
<b>pages</b>
|
||||||
|
{% for page in section.pages %}
|
||||||
|
<a href="{{page.path}}">{{page.title}}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</nav>
|
||||||
|
<main>
|
||||||
|
<h1>{{ page.title }}</h1>
|
||||||
|
{{ page.content | safe }}
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
56
templates/index.html
Normal file
56
templates/index.html
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}home{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<header>
|
||||||
|
</header>
|
||||||
|
<section id="blurb">
|
||||||
|
<h1>jackwagon is federated e2ee thread only chats done right</h1>
|
||||||
|
<a href="#" style="background:#822eba">try it out</a> <a href="/docs/hello">read docs</a>
|
||||||
|
</section>
|
||||||
|
<section id="video">
|
||||||
|
<video src="./psyqui.mp4" controls></video>
|
||||||
|
</section>
|
||||||
|
<section id="about">
|
||||||
|
<div>
|
||||||
|
<h2>why</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Like zulip or discord forum channels, but but taken to its logical conclusion</li>
|
||||||
|
<li>Federated/decentralized and built to last</li>
|
||||||
|
<li>Aiming to be a complete and usable system out of the box, with minimal setup or maintenence</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2>why not</h2>
|
||||||
|
<ul>
|
||||||
|
<li>It kinda does its own thing and won't easily replace $APP</li>
|
||||||
|
<li>It's yet another platform that you'll have to convince your friends to use</li>
|
||||||
|
<li>Extremely early alpha that probably shouldn't even been released</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2>other info</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Forked from <a href="https://matrix.org">matrix</a> and <a href="https://conduit.rs">conduit</a> (but incompatible!)</li>
|
||||||
|
<li>Free and open source software</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<svg width="100%" height="10px">
|
||||||
|
<line id="line" stroke-dasharray="
|
||||||
|
10, 10, 30, 10, 30, 10, 30, 30,
|
||||||
|
10, 10, 30, 30,
|
||||||
|
30, 10, 10, 10, 30, 10, 10, 30,
|
||||||
|
30, 10, 10, 10, 30, 30,
|
||||||
|
10, 10, 30, 10, 30, 30,
|
||||||
|
10, 10, 30, 30,
|
||||||
|
30, 10, 30, 10, 10, 30,
|
||||||
|
30, 10, 30, 10, 30, 30,
|
||||||
|
30, 10, 10, 30"
|
||||||
|
x1="0" y1="5px" x2="100%" y2="5px"
|
||||||
|
style="stroke: var(--background-2)" stroke-width="10"
|
||||||
|
stroke-dashoffset="0"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{% endblock %}
|
Loading…
Reference in a new issue