Files
plainleaf/client/styles/_standalone.scss
T

440 lines
9.9 KiB
SCSS

// Page chrome for the standalone (non-editor) pages: the login page, the setup
// wizard and the Space Manager. Everything here is scoped under
// `body.sb-standalone` so this partial can share one stylesheet with the plug
// panels, which are the same components without the page furniture.
@use "tokens";
body.sb-standalone {
--top-color: #66a3bb;
--bottom-color: #0b3a69;
min-height: 100vh;
background: linear-gradient(to bottom, var(--top-color), var(--bottom-color));
font-family: var(--ui-font);
// The gradient lives on <body> rather than <html> so it can be scoped by a
// class; <html> only needs to stop collapsing under it.
*,
*::before,
*::after {
box-sizing: border-box;
}
h1 {
font-size: 1.5rem;
font-weight: normal;
}
// Subsection heading (e.g. "Role", "Password", "API tokens" on the user
// detail screen) — a clear step below the page title, not level with it.
h2 {
font-size: 1.15rem;
font-weight: 600;
}
h3 {
font-size: 1.05rem;
font-weight: 600;
margin-top: 1.5rem;
}
// Vertical rhythm between subsections (the user detail screen's
// Role/Password/API tokens blocks) so they read as distinct groups.
section {
margin-top: 1.75rem;
}
details {
margin-top: 1rem;
}
// Every list on these pages is a custom `list-style: none` layout, never
// prose, so the UA's ~40px marker indent is pure dead space on the left.
// The old bundle got this from a global `* { padding: 0 }` reset; that reset
// is gone (it broke the editor), so state it where it actually applies.
ul,
ol {
padding-left: 0;
}
// The component library has no Radio, so the setup wizard's hosting choice
// uses native radios — just tint them to match .sb-checkbox.
input[type="radio"] {
accent-color: var(--ui-accent-color);
cursor: pointer;
}
form label {
display: block;
margin-top: 0.75rem;
font-weight: 600;
}
// Full-width fields inside forms; the components supply everything else.
form .sb-input,
form .sb-select {
width: 100%;
}
.row {
display: flex;
gap: 0.5rem;
margin-top: 1rem;
align-items: center;
}
// Links used for navigation should look like their button counterparts while
// retaining normal link behaviour (copy, open in a new tab, history).
a.sb-button,
a.sb-button-primary {
display: inline-flex;
align-items: center;
justify-content: center;
text-decoration: none;
}
a.sb-tab {
text-decoration: none;
}
.sb-help-text {
display: block;
margin-top: 0.25rem;
font-weight: normal;
color: var(--subtle-color);
font-size: 0.9em;
}
.sb-spaces-error {
color: #b00020;
}
.sb-spaces-ok {
color: #1a7f37;
// Live regions are rendered before they have anything to announce; an
// empty one must not claim a flex gap next to the buttons it follows.
&:empty {
display: none;
}
}
.sb-spaces-warn {
color: #9a6700;
}
}
// The 720px reading column, used by the setup wizard and the Space Manager.
// The login page opts out: it centres a card in the viewport instead.
body.sb-standalone.sb-page {
max-width: 720px;
margin: 0 auto;
padding: 2rem 1rem;
}
// The "floating island" card. On the column pages (Space Manager, setup
// wizard) the mount point *is* the card; the login page mounts a full-viewport
// centring wrapper instead and puts .floating-island inside it, so `#root` is
// qualified with .sb-page to avoid drawing a second card around the first.
.sb-standalone .floating-island,
.sb-standalone.sb-page #root {
padding: 3em;
border-radius: 8px;
box-shadow: rgba(0, 0, 0, 0.35) 0px 20px 20px;
background-color: white;
border: var(--modal-border-color) 1px solid;
margin-block: 2rem;
}
.sb-standalone .center {
height: 100vh;
display: grid;
place-items: center;
}
.sb-standalone .flow {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.sb-standalone .flow>* {
margin-block: 0;
}
.sb-standalone .flow>*+* {
margin-block-start: var(--space, 1rem);
}
.sb-standalone .error-message {
color: #b00020;
}
.sb-standalone .checkbox-wrapper {
display: flex;
align-items: center;
gap: 0.5rem;
flex-direction: row;
}
// A checkbox's label sits beside it, not above it: undo the block layout,
// top margin and bold weight that `form label` gives the field labels, which
// otherwise push the text out of line with the box and make every option
// shout.
.sb-standalone .checkbox-wrapper label,
.sb-standalone form .checkbox-wrapper label {
display: inline;
margin: 0;
font-weight: normal;
}
.sb-standalone .password-field {
display: flex;
gap: 0.5rem;
align-items: center;
}
.sb-standalone .password-field .sb-input {
flex: 1;
}
/* Header: wordmark (+ admin tab bar) on the left, quiet log-out link on the
right.
The gap below is 1rem, not the 2rem this had while the screens below it
opened with an <h1>. Those headings are gone from the list screens (the tab
bar names them), so 2rem left the content stranded — and on a list the first
row adds another 0.5rem of its own padding before any text. */
.sb-standalone .sb-spaces-header {
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #8884;
margin-bottom: 1rem;
}
.sb-standalone .sb-spaces-header-left {
display: flex;
align-items: center;
gap: 1.5rem;
}
.sb-standalone .sb-wordmark {
display: inline-flex;
align-items: center;
gap: 0.4em;
font-size: 1.1rem;
// The dock icon already carries its own rounded corners and padding, so it
// needs no framing here — only a size that sits with the wordmark's cap
// height rather than towering over it.
img {
width: 1.5em;
height: 1.5em;
}
}
/* Aligned columns: name | binding link | status | edit action. Each row is a
subgrid so cells line up across rows while rows keep their borders.
Non-admin rows simply leave the last column empty. */
.sb-standalone .sb-space-list {
list-style: none;
display: grid;
grid-template-columns: 1fr max-content max-content max-content;
}
.sb-standalone .sb-space-list li {
display: grid;
grid-template-columns: subgrid;
grid-column: 1 / -1;
align-items: center;
column-gap: 1rem;
padding: 0.5rem 0;
border-bottom: 1px solid #8884;
}
/* Space name: opens the space itself for every account, admin or not. */
.sb-standalone .sb-space-link {
color: var(--ui-accent-color);
font-weight: 600;
}
/* Admin-only per-row edit control, right-aligned at the end of the row. */
.sb-standalone .sb-space-edit {
justify-self: end;
}
/* Bottom-of-form destructive zone. Delete stays visually destructive (via
.sb-button-danger's colour) but is sized like every other button — it
shouldn't dominate the page. */
.sb-standalone .sb-danger-zone {
margin-top: 2rem;
padding-top: 1.25rem;
border-top: 1px solid #8884;
}
.sb-standalone .sb-badge.errored {
background-color: #b0002033;
color: #b00020;
}
/* Server-side folder picker (client/spaces_ui/FolderPicker.tsx). */
.sb-standalone .sb-folder-picker-status {
display: flex;
align-items: center;
gap: 0.75rem;
margin-top: 0.25rem;
font-size: 0.9em;
}
.sb-standalone .sb-link-button {
background: none;
color: var(--ui-accent-color);
border: none;
box-shadow: none;
padding: 0;
font-size: inherit;
font-family: inherit;
text-decoration: underline;
cursor: pointer;
}
.sb-standalone .sb-link-button:hover {
background: none;
}
/* No focus ring on mouse clicks; keep a subtle one for keyboard focus. */
.sb-standalone .sb-link-button:focus {
outline: none;
box-shadow: none;
}
.sb-standalone .sb-link-button:focus-visible {
outline: 2px solid var(--ui-accent-color);
outline-offset: 2px;
border-radius: 2px;
}
.sb-standalone .sb-folder-browser {
margin-top: 0.5rem;
border: 1px solid #ddd;
border-radius: 4px;
padding: 0.5rem 0.75rem;
background: #fafafa;
}
.sb-standalone .sb-folder-crumbs {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.25rem;
margin-bottom: 0.5rem;
}
.sb-standalone .sb-folder-crumb-sep {
color: #999;
}
.sb-standalone .sb-folder-dirs {
list-style: none;
max-height: 12rem;
overflow-y: auto;
margin: 0;
}
.sb-standalone .sb-folder-dirs li {
padding: 0.15rem 0;
}
.sb-standalone .sb-folder-empty {
color: var(--subtle-color);
font-style: italic;
}
/* Users table. */
.sb-standalone .sb-user-table {
width: 100%;
border-collapse: collapse;
margin-top: 1rem;
}
.sb-standalone .sb-user-table th {
text-align: left;
font-weight: 600;
font-size: 0.85em;
color: #555;
padding: 0.35rem 0.5rem;
}
.sb-standalone .sb-user-table td {
padding: 0.35rem 0.5rem;
border-bottom: 1px solid #8884;
vertical-align: middle;
}
// Name reads as the primary control; the Edit button repeats it at the row's
// end, right-aligned like the spaces list.
.sb-standalone .sb-user-link {
color: var(--ui-accent-color);
font-weight: 600;
}
.sb-standalone .sb-user-table td:last-child {
text-align: right;
width: 1%;
white-space: nowrap;
}
.sb-standalone .sb-user-table label {
display: inline-flex;
align-items: center;
gap: 0.3em;
margin: 0;
font-weight: normal;
}
.sb-standalone .sb-token-list {
padding: 0.5rem;
background: #f7f7f7;
border-radius: 0.4em;
list-style: none;
margin: 0 0 0.5rem;
}
.sb-standalone .sb-token-list li {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.25rem 0;
}
.sb-standalone .sb-token-reveal {
display: flex;
flex-direction: column;
gap: 0.25rem;
margin-top: 0.5rem;
}
.sb-standalone .sb-token-reveal .sb-input {
font-family: monospace;
}
.sb-standalone .sb-member-list {
border: 1px solid #ddd;
border-radius: 0.4em;
padding: 0.5rem 0.75rem;
margin-top: 0.5rem;
}
.sb-standalone .sb-member-list legend {
font-weight: 600;
padding: 0 0.3em;
}
.sb-standalone .sb-member-row {
display: flex;
align-items: center;
gap: 0.4em;
margin: 0.25rem 0;
font-weight: normal;
}