Kokkoja as of 2026-10-10: the teacher's requests, the Session window, notices, the QR code, the license
This commit is contained in:
1 parent
95c80d04c9
commit
1d087af633
32 files changed
+4917
-890
No files matched your search
+135
-70
@@ -5,8 +5,7 @@
|
||||
--panel: #f6f6f7;
|
||||
--desk: #e4e4e7;
|
||||
--accent: #1f4fd8;
|
||||
--text_edge: #ababab; /* The top edge of a text block being edited: 67% grey. */
|
||||
--text_handle: #ababab; /* Its squares: the same. */
|
||||
--text_frame: #e53935; /* A text rectangle's frame: the palette's red. */
|
||||
font-family: system-ui, sans-serif;
|
||||
font-size: 15px;
|
||||
color: var(--ink);
|
||||
@@ -20,6 +19,14 @@ html, body { height: 100%; margin: 0; }
|
||||
|
||||
button, input { font: inherit; color: inherit; }
|
||||
|
||||
/* A drag across the controls selects nothing: their text is not for
|
||||
copying (Andy, 2026-10-07). Fields stay selectable. Safari on iOS
|
||||
and iPadOS knows only the prefixed property (MDN's compatibility
|
||||
data, 2026-10-10); without it the Pencil's first movement sometimes
|
||||
selected the save status on Andy's iPad. */
|
||||
button, select, label, .toolbar, .panel h2, #participants, .chooser header
|
||||
{ -webkit-user-select: none; user-select: none; }
|
||||
|
||||
button {
|
||||
padding: 0.35rem 0.8rem;
|
||||
border: 1px solid var(--line);
|
||||
@@ -35,12 +42,14 @@ button[aria-pressed="true"] {
|
||||
box-shadow: inset 0 0 0 1px var(--accent);
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
input[type="text"], select.notebook_pick {
|
||||
width: 100%;
|
||||
padding: 0.4rem 0.5rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: white;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@@ -80,15 +89,29 @@ h2 {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* One row, holding everything (Andy's teacher, 2026-10-08: the whole
|
||||
width of the window belongs to the page); it wraps only when the window
|
||||
is too narrow for it. */
|
||||
.toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 1.25rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
gap: 0.5rem 0.55rem;
|
||||
padding: 0.4rem 0.5rem;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: var(--panel);
|
||||
}
|
||||
|
||||
/* When the window is too narrow for one row, the tools are centred
|
||||
instead of standing at the two ends (Andy, 2026-10-09; main.js sets
|
||||
the class by measuring). */
|
||||
.toolbar.wrapped { justify-content: center; }
|
||||
.toolbar.wrapped .toolbar_right { margin-left: 0; justify-content: center; }
|
||||
|
||||
.toolbar .notebook_pick { width: 9rem; }
|
||||
.toolbar .toggle { display: flex; align-items: center; gap: 0.3rem; cursor: pointer; }
|
||||
.toolbar .toggle input { margin: 0; }
|
||||
|
||||
.group { display: flex; align-items: center; gap: 0.35rem; }
|
||||
|
||||
.swatch {
|
||||
@@ -100,13 +123,16 @@ h2 {
|
||||
background-clip: content-box;
|
||||
}
|
||||
|
||||
/* The same height as the buttons, so the toolbar does not change height. */
|
||||
/* The same height as the buttons, so the toolbar does not change height;
|
||||
narrow enough that a host's toolbar fits a 1920-pixel screen in one
|
||||
row (measured 2026-10-09: about 1750 pixels with these settings). */
|
||||
.toolbar button:not(.swatch), #text_size, #text_font {
|
||||
box-sizing: border-box;
|
||||
height: 2rem;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.toolbar button:not(.swatch) { padding-left: 0.6rem; padding-right: 0.6rem; }
|
||||
|
||||
#text_size, #text_font {
|
||||
margin: 0;
|
||||
@@ -137,6 +163,8 @@ h2 {
|
||||
}
|
||||
|
||||
.palette .swatch { width: 1.5rem; height: 1.5rem; }
|
||||
/* A colour already in the toolbar leaves its place in the grid empty. */
|
||||
.palette .swatch.missing { visibility: hidden; }
|
||||
|
||||
.swatch.more {
|
||||
--swatch: white;
|
||||
@@ -161,24 +189,36 @@ h2 {
|
||||
background: var(--ink);
|
||||
}
|
||||
|
||||
#zoom_in, #zoom_out {
|
||||
width: 2.2rem;
|
||||
padding: 0.1rem 0;
|
||||
font-size: 1.35rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
/* What concerns the page and the view, not the tool: it never moves. */
|
||||
/* The page, the notebook and the session: flush right, the page number
|
||||
and what is going on at the very end (Andy, 2026-10-08). */
|
||||
.toolbar_right {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 1.25rem;
|
||||
gap: 0.5rem 0.55rem;
|
||||
margin-left: auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.page_number { color: var(--muted); }
|
||||
.status { min-width: 6.5rem; text-align: right; color: var(--muted); }
|
||||
.status.problem { color: #b42318; }
|
||||
/* The notice line between the toolbar and the page: nothing, and no
|
||||
room, while all is well; a problem in red while it lasts; a
|
||||
confirmation for a few seconds (Andy, 2026-10-10: the toolbar's
|
||||
"Page 3 Connected Saved at …" was noise, and the room is needed for
|
||||
one row). */
|
||||
.notice {
|
||||
padding: 0.3rem 1rem;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: var(--panel);
|
||||
text-align: center;
|
||||
font-size: 0.9rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
.notice.problem { color: #b42318; }
|
||||
|
||||
/* The quiet facts in the Session window: the page, the connection, the
|
||||
last save. */
|
||||
.session_state span { margin-right: 1rem; white-space: nowrap; }
|
||||
.session_state .problem { color: #b42318; }
|
||||
|
||||
.workspace {
|
||||
display: flex;
|
||||
@@ -190,17 +230,40 @@ h2 {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: auto;
|
||||
padding: 1.25rem;
|
||||
padding: 0.5rem;
|
||||
background: var(--desk);
|
||||
}
|
||||
|
||||
/* The cue around an image being moved or scaled by hand: green, with a
|
||||
square at the corner being dragged. */
|
||||
.image_grip {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
box-sizing: border-box;
|
||||
border: 2px solid #2e7d32;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.image_grip.corner::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: var(--corner-x);
|
||||
top: var(--corner-y);
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
transform: translate(-50%, -50%);
|
||||
background: #2e7d32;
|
||||
}
|
||||
|
||||
.page {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
box-shadow: 0 1px 4px rgb(0 0 0 / 0.25);
|
||||
touch-action: none;
|
||||
-webkit-user-select: none; /* Safari on iOS: see the controls rule. */
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none; /* No callout from a long press of the Pencil. */
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
@@ -228,75 +291,78 @@ h2 {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.text_handle {
|
||||
/* A rectangle being dragged open, for text or for Hide. */
|
||||
.rect_preview {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin: -5px 0 0 -5px;
|
||||
border: 1px solid white;
|
||||
border-radius: 2px;
|
||||
background: var(--text_handle);
|
||||
cursor: move;
|
||||
box-sizing: border-box;
|
||||
border: 2px dotted #ababab;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.text_handle.end { cursor: ew-resize; }
|
||||
/* The field of a text rectangle shows its frame and white ground itself,
|
||||
since the renderer leaves the block out while it is edited. */
|
||||
.text_field.rect {
|
||||
background: white;
|
||||
outline-style: solid;
|
||||
outline-color: var(--text_frame);
|
||||
}
|
||||
|
||||
.text_edge {
|
||||
/* Free text's corner mark while it is edited: an L at its top-left corner. */
|
||||
.text_mark {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
height: 0;
|
||||
margin-top: -1px;
|
||||
border-top: 2px solid var(--text_edge);
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.text_edge::before, .text_edge::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 0;
|
||||
height: 8px;
|
||||
border-left: 2px solid var(--text_edge);
|
||||
}
|
||||
|
||||
.text_edge::before { left: 0; }
|
||||
.text_edge::after { right: 0; }
|
||||
|
||||
/* The top edge of a new block, while it is being dragged out. */
|
||||
.text_preview {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
height: 0;
|
||||
margin-top: -1px;
|
||||
border-top: 2px solid var(--text_edge);
|
||||
box-sizing: border-box;
|
||||
border-style: solid none none solid;
|
||||
border-color: var(--text_frame);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
||||
.panel {
|
||||
width: 16rem;
|
||||
padding: 0 1rem 1rem;
|
||||
overflow: auto;
|
||||
border-left: 1px solid var(--line);
|
||||
background: var(--panel);
|
||||
}
|
||||
/* The Session dialog: who is here, and the invitation. */
|
||||
|
||||
.panel ul { margin: 0; padding: 0; list-style: none; }
|
||||
/* fit-content, not auto: a modal dialog has its top and bottom pinned by
|
||||
the browser's own style, so an auto height filled the window up to the
|
||||
maximum (seen 2026-10-10: 1100 px of dialog around 350 px of content). */
|
||||
.chooser.session { width: min(32rem, 90vw); height: fit-content; max-height: 85vh; }
|
||||
.session_body h3 { margin: 1rem 0 0.4rem; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
|
||||
.session_body ul { margin: 0; padding: 0; list-style: none; }
|
||||
|
||||
.panel li {
|
||||
.session_body li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.2rem 0;
|
||||
}
|
||||
|
||||
.panel li.absent { color: var(--muted); }
|
||||
.panel li label { flex: 1; }
|
||||
.panel li .role { font-size: 0.8rem; color: var(--muted); }
|
||||
.panel li .allow { order: 1; padding: 0.1rem 0.4rem; font-size: 0.75rem; }
|
||||
|
||||
.panel button { margin-top: 0.4rem; }
|
||||
.session_body li.absent { color: var(--muted); }
|
||||
.session_body li label { flex: 1; }
|
||||
.session_body li .role { font-size: 0.8rem; color: var(--muted); }
|
||||
.session_body li .allow_line { order: 1; display: flex; align-items: center; gap: 0.3rem; font-size: 0.8rem; color: var(--muted); cursor: pointer; }
|
||||
.session_body li .allow_line input { margin: 0; }
|
||||
.invitation_line { display: flex; gap: 0.5rem; align-items: center; }
|
||||
.invitation_line input { flex: 1; min-width: 0; }
|
||||
/* The invitation as a QR code, for the camera of a phone or a tablet. */
|
||||
.invitation_code { width: min(13rem, 60vw); margin: 0.75rem auto 0; }
|
||||
.invitation_code svg { display: block; width: 100%; height: auto; }
|
||||
/* The log, the latest entry at the bottom and in view, selectable. */
|
||||
.log_line { display: flex; gap: 0.5rem; align-items: flex-start; }
|
||||
.event_log {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
max-height: 10rem;
|
||||
overflow: auto;
|
||||
padding: 0.3rem 0.4rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
font-size: 0.7rem;
|
||||
line-height: 1.35;
|
||||
color: var(--muted);
|
||||
white-space: pre;
|
||||
-webkit-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
/* The notebook chooser */
|
||||
|
||||
@@ -396,7 +462,6 @@ h2 {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.files_shrink { display: block; margin-top: 0.75rem; font-size: 0.9rem; }
|
||||
|
||||
.files_existing {
|
||||
display: flex;
|
||||
|
||||
Reference in new issue
Block a user