Projects live at URLs, have owners, and are edited together live
A project is only ever at /p/<id>/<slug>; / is the index of the projects
you own or edit. Every project has an owner, who can name editors;
anyone with the link can view. Every edit saves itself, one request in
flight at a time, as a patch of the leaves that changed, and a websocket
(channels + daphne) carries presence and each committed write to
everyone else in the project. The first write to a leaf wins, and the
loser is told.
Undo is per person: a step undoes only if the leaves it touched still
hold what it left, so it never takes a collaborator's work with it.
Named snapshots replace saving, and restore as an ordinary write.
An empty symbol now survives the leaf round trip with `:nodes {}`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
c17ee138f2
commit
6a53adb5e0
31 changed files with 1918 additions and 158 deletions
|
|
@ -252,6 +252,50 @@ input[type="range"] { width: 100%; accent-color: var(--sel); }
|
|||
.menu-item.example { font-style: italic; }
|
||||
.menu-item .sub { display: block; color: var(--dim); }
|
||||
|
||||
/* Rows about the document rather than choices in it: who can edit. */
|
||||
.menu-item.static { display: flex; align-items: center; gap: 6px; cursor: default; }
|
||||
.menu-item.static:hover { background: none; }
|
||||
.menu-item.static .sub { display: inline; margin-left: auto; }
|
||||
.menu-item.static button { margin-left: auto; }
|
||||
.menu .row { margin: 4px 0; flex-wrap: nowrap; }
|
||||
.menu .row input { flex: 1; min-width: 0; }
|
||||
.menu p { margin: 4px 0; }
|
||||
.account { display: grid; gap: 4px; }
|
||||
button.link { border: 0; background: none; padding: 0; color: var(--sel); cursor: pointer; }
|
||||
|
||||
/* `/`: your projects, over the editor. */
|
||||
.index { position: fixed; inset: 0; z-index: 30; display: flex; flex-direction: column;
|
||||
background: var(--pane); }
|
||||
.index-body { width: min(640px, 100%); margin: 0 auto; padding: 24px 16px; overflow: auto; }
|
||||
.index-body h1 { font: inherit; font-size: 18px; font-weight: 600; margin: 0 0 12px; }
|
||||
.index-head { display: flex; align-items: baseline; justify-content: space-between; }
|
||||
.index-list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--hair); }
|
||||
.index-list li { display: flex; justify-content: space-between; gap: 12px;
|
||||
padding: 7px 2px; border-bottom: 1px solid var(--hair); }
|
||||
.index-list a { color: var(--fg); text-decoration: none; font-weight: 600; }
|
||||
.index-list a:hover { color: var(--sel); }
|
||||
a.brand { text-decoration: none; }
|
||||
|
||||
/* Undo, its list, redo: one group. */
|
||||
.undo { display: flex; gap: 0; }
|
||||
.undo > button { border-radius: 0; }
|
||||
.undo > button:first-child { border-radius: 2px 0 0 2px; }
|
||||
.undo > .undo-list { padding: 0 4px; margin-right: 4px; border-left: 0; border-radius: 0 2px 2px 0; }
|
||||
.menu.menu-left { left: 0; right: auto; }
|
||||
|
||||
/* The one way to hand the document to somebody else, so it looks like one. */
|
||||
button.share-button { background: var(--sel); color: #fff; border-color: var(--sel); font-weight: 600; padding: 1px 12px; }
|
||||
button.share-button:hover, button.share-button.on { filter: brightness(1.1); }
|
||||
|
||||
/* Who else has this document open. */
|
||||
.roster { display: flex; gap: 2px; align-items: center; }
|
||||
.peer {
|
||||
width: 18px; height: 18px; border-radius: 50%;
|
||||
display: inline-grid; place-items: center;
|
||||
background: var(--sel); color: #fff; font-size: 10px; font-weight: 600;
|
||||
}
|
||||
.peer.guest { background: var(--dim); }
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
media pool */
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue