880 lines
18 KiB
CSS
880 lines
18 KiB
CSS
/* index.css - styles for index.html and generally main parts of the app
|
|
For shared styles (such as color definitions) check out base.css. */
|
|
|
|
html {
|
|
/* On the main page, we don't really want to permit selecting things.
|
|
It comes off as janky-looking. */
|
|
user-select: none;
|
|
}
|
|
|
|
/* Main container layout */
|
|
|
|
html {
|
|
/* Don't want any scrollbars to ruin our layout.
|
|
Technically this will cause jank in case the view _does_ scroll somehow, but that's less of
|
|
an annoying bug than browser layout triggering scrollbars and ruining the page size...
|
|
I'm not sure what caused the browser to show scrollbars when I switched my displays to 4k,
|
|
but it did, and I didn't like it.
|
|
CSS remains a mystery, as it always has. */
|
|
overflow: hidden;
|
|
}
|
|
|
|
body {
|
|
width: 100vw;
|
|
height: 100vh;
|
|
|
|
font-size: 14px;
|
|
}
|
|
|
|
main {
|
|
width: 100%;
|
|
height: 100%;
|
|
position: relative;
|
|
|
|
& > .fullscreen {
|
|
width: 100%;
|
|
height: 100%;
|
|
max-width: 100%;
|
|
max-height: 100%;
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
}
|
|
|
|
& > .panels {
|
|
--right-width: 384px; /* Overridden by JavaScript */
|
|
|
|
display: grid;
|
|
grid-template-columns: [left] 1fr [right-resize] auto [right] minmax(
|
|
0,
|
|
var(--right-width)
|
|
);
|
|
|
|
/* Pass all events through. Children may receive events as normal. */
|
|
pointer-events: none;
|
|
|
|
& > * {
|
|
pointer-events: all;
|
|
}
|
|
|
|
& > .left {
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 16px;
|
|
|
|
pointer-events: none;
|
|
& > * {
|
|
pointer-events: auto;
|
|
}
|
|
|
|
& > rkgk-zoom-indicator {
|
|
margin-block-start: auto;
|
|
}
|
|
}
|
|
|
|
& > .right {
|
|
grid-column: right / right;
|
|
min-height: 0;
|
|
|
|
display: grid;
|
|
grid-template-rows: 100%;
|
|
grid-template-columns: [resize] min-content [docked] auto;
|
|
|
|
padding-left: 16px;
|
|
|
|
pointer-events: none;
|
|
|
|
& > * {
|
|
min-width: 0;
|
|
min-height: 0;
|
|
}
|
|
|
|
& > .floating {
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
gap: 12px;
|
|
|
|
padding: 16px;
|
|
|
|
& > rkgk-brush-preview {
|
|
width: 128px;
|
|
height: 128px;
|
|
pointer-events: auto;
|
|
}
|
|
|
|
& > rkgk-brush-cost-gauges {
|
|
width: 100%;
|
|
pointer-events: auto;
|
|
}
|
|
}
|
|
|
|
& > rkgk-resize-handle {
|
|
pointer-events: auto;
|
|
}
|
|
|
|
& > .docked {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
max-height: 100%;
|
|
|
|
background-color: var(--color-panel-background);
|
|
box-shadow: 0 0 0 1px var(--color-panel-border);
|
|
|
|
pointer-events: auto;
|
|
|
|
& > * {
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
& > rkgk-brush-editor {
|
|
flex-grow: 1;
|
|
flex-shrink: 1;
|
|
}
|
|
|
|
& > .menu-bar {
|
|
border-bottom: 1px solid var(--color-panel-border);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
& > rkgk-canvas-renderer {
|
|
width: 100%;
|
|
height: 100%;
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
}
|
|
|
|
& > rkgk-reticle-renderer {
|
|
width: 100%;
|
|
height: 100%;
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
& > #js-loading {
|
|
background-color: var(--color-panel-background);
|
|
z-index: var(--z-modal);
|
|
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
}
|
|
|
|
/* Resize handle */
|
|
|
|
rkgk-resize-handle {
|
|
--width: 8px;
|
|
--line: none;
|
|
|
|
display: flex;
|
|
justify-content: center;
|
|
flex-shrink: 0;
|
|
|
|
z-index: var(--z-resize-handle);
|
|
|
|
&.always-visible {
|
|
--line: 1px solid var(--color-panel-border);
|
|
}
|
|
|
|
&[data-direction="horizontal"] {
|
|
width: 100%;
|
|
height: var(--width);
|
|
margin: calc(var(--width) / -2) 0;
|
|
|
|
flex-direction: column;
|
|
|
|
cursor: row-resize;
|
|
|
|
& > .visual {
|
|
width: 100%;
|
|
height: 0;
|
|
border-bottom: var(--line);
|
|
}
|
|
}
|
|
|
|
&[data-direction="vertical"] {
|
|
width: var(--width);
|
|
height: 100%;
|
|
margin: 0 calc(var(--width) / -2);
|
|
|
|
flex-direction: row;
|
|
|
|
cursor: col-resize;
|
|
|
|
& > .visual {
|
|
width: 0;
|
|
height: 100%;
|
|
border-left: var(--line);
|
|
}
|
|
}
|
|
|
|
&:hover > .visual,
|
|
&.dragging > .visual {
|
|
--line: 2px solid var(--color-brand-blue);
|
|
}
|
|
}
|
|
|
|
/* Canvas renderer */
|
|
|
|
rkgk-canvas-renderer {
|
|
display: block;
|
|
|
|
& > canvas {
|
|
display: block;
|
|
|
|
/* Fill the parent, don't overflow it.
|
|
This is important because under HiDPI, the canvas's pixel size is larger than the layout size. */
|
|
max-width: 100%;
|
|
max-height: 100%;
|
|
}
|
|
}
|
|
|
|
/* Reticle renderer */
|
|
|
|
rkgk-reticle-renderer {
|
|
display: block;
|
|
|
|
pointer-events: none;
|
|
|
|
& > .reticles {
|
|
position: relative;
|
|
}
|
|
}
|
|
|
|
rkgk-reticle-cursor {
|
|
--color: black; /* Overridden by JavaScript to set a per-user color. */
|
|
|
|
position: absolute;
|
|
display: block;
|
|
|
|
& > .container {
|
|
& > .arrow {
|
|
width: 24px;
|
|
height: 24px;
|
|
background-color: var(--color);
|
|
clip-path: path("M 0,0 L 13,13 L 6,13 L 0,19 Z");
|
|
}
|
|
|
|
& > .nickname {
|
|
position: absolute;
|
|
top: 20px;
|
|
left: 8px;
|
|
width: max-content;
|
|
|
|
color: white;
|
|
background-color: var(--color);
|
|
padding: 1px 6px;
|
|
border-radius: 9999px;
|
|
text-align: center;
|
|
font-weight: bold;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Brush box */
|
|
|
|
rkgk-brush-box {
|
|
--button-size: 56px;
|
|
|
|
height: var(--height);
|
|
padding: 12px;
|
|
|
|
overflow-x: hidden;
|
|
overflow-y: auto;
|
|
|
|
& > .brushes {
|
|
display: grid;
|
|
grid-template-columns: repeat(
|
|
auto-fit,
|
|
minmax(var(--button-size), 1fr)
|
|
);
|
|
|
|
max-height: 100%;
|
|
|
|
& > button {
|
|
padding: 0;
|
|
border: 1px solid transparent;
|
|
border-radius: 4px;
|
|
width: 100%;
|
|
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
|
|
&.current {
|
|
border-color: var(--color-brand-blue);
|
|
}
|
|
|
|
& > rkgk-brush-preview {
|
|
width: var(--button-size);
|
|
aspect-ratio: 1 / 1;
|
|
background: none;
|
|
}
|
|
|
|
& > .label {
|
|
margin: 0;
|
|
font-size: 80%;
|
|
}
|
|
|
|
&.save-button {
|
|
display: none; /* visible when current brush is modified */
|
|
|
|
& > .icon {
|
|
width: var(--button-size);
|
|
height: var(--button-size);
|
|
}
|
|
|
|
& > .icon,
|
|
& > .label {
|
|
opacity: 35%;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
&.unsaved > .brushes {
|
|
& > .current > .label::after {
|
|
content: "*";
|
|
}
|
|
|
|
& > .save-button {
|
|
display: flex;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Code editor */
|
|
|
|
rkgk-code-editor {
|
|
--gutter-width: 3.5em;
|
|
--vertical-padding: 12px;
|
|
|
|
display: block;
|
|
position: relative;
|
|
|
|
padding: var(--vertical-padding) 0;
|
|
overflow: auto;
|
|
|
|
& > .layer {
|
|
position: absolute;
|
|
left: 0;
|
|
top: var(--vertical-padding);
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
|
|
margin: 0;
|
|
|
|
pointer-events: none;
|
|
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
& > .line {
|
|
flex-shrink: 0;
|
|
white-space: pre-wrap;
|
|
|
|
min-height: var(--line-height-em);
|
|
}
|
|
}
|
|
|
|
& > .layer-gutter {
|
|
counter-reset: line;
|
|
|
|
color: transparent;
|
|
|
|
& > .line {
|
|
display: flex;
|
|
flex-direction: row;
|
|
|
|
counter-increment: line;
|
|
|
|
&::before {
|
|
flex-shrink: 0;
|
|
|
|
display: block;
|
|
width: var(--gutter-width);
|
|
padding-right: 0.75em;
|
|
box-sizing: border-box;
|
|
|
|
content: counter(line);
|
|
text-align: right;
|
|
|
|
color: var(--color-text);
|
|
opacity: 40%;
|
|
}
|
|
}
|
|
}
|
|
|
|
& > .layer:not(.layer-gutter) {
|
|
margin-left: var(--gutter-width);
|
|
width: calc(100% - var(--gutter-width));
|
|
}
|
|
|
|
& > .layer-error-squiggles {
|
|
color: transparent;
|
|
|
|
& > .line {
|
|
& > .squiggle {
|
|
text-decoration: underline wavy black;
|
|
text-decoration-skip-ink: none;
|
|
}
|
|
|
|
& > .squiggle-error {
|
|
text-decoration-color: var(--color-error);
|
|
|
|
&.squiggle-colored {
|
|
--color: oklch(40% 100% calc(var(--color-index) * 300));
|
|
text-decoration-color: var(--color);
|
|
background-color: oklch(from var(--color) 60% c h / 0.13);
|
|
|
|
&.squiggle-highlighted {
|
|
--highlight-color-index: var(--color-index);
|
|
text-decoration: none;
|
|
background-color: oklch(
|
|
40% 100% calc(var(--highlight-color-index) * 300)
|
|
);
|
|
color: white;
|
|
font-weight: bold;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
& > .layer-syntax {
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
& > textarea {
|
|
display: block;
|
|
width: calc(100% - var(--gutter-width));
|
|
|
|
margin: 0;
|
|
margin-left: var(--gutter-width);
|
|
padding: 0;
|
|
border: none;
|
|
|
|
overflow: hidden;
|
|
resize: none;
|
|
|
|
white-space: pre-wrap;
|
|
|
|
background: none;
|
|
color: transparent;
|
|
caret-color: var(--color-text);
|
|
|
|
&:focus {
|
|
/* The outline is displayed on the parent element to also surround the gutter. */
|
|
outline: none;
|
|
}
|
|
|
|
&::selection {
|
|
/* The selection color has to be overridden for a good contrast ratio between text and
|
|
the selection. */
|
|
background-color: rgba(from var(--color-brand-blue) r g b / 0.3);
|
|
}
|
|
}
|
|
|
|
&:has(textarea:focus) {
|
|
outline: 1px solid var(--color-brand-blue);
|
|
outline-offset: -1px;
|
|
}
|
|
}
|
|
|
|
/* Brush editor */
|
|
|
|
rkgk-brush-editor {
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
min-height: 0;
|
|
|
|
position: relative;
|
|
|
|
& > .editor {
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
height: calc(100% - var(--brush-preview-height));
|
|
|
|
& > .name {
|
|
margin: 12px;
|
|
margin-bottom: 0;
|
|
font-weight: bold;
|
|
}
|
|
|
|
& > rkgk-code-editor {
|
|
height: 100%;
|
|
flex-shrink: 1;
|
|
}
|
|
}
|
|
|
|
& > output {
|
|
height: 64px;
|
|
flex-grow: 1;
|
|
|
|
user-select: text;
|
|
|
|
&[data-state="ok"] > .errors {
|
|
display: none;
|
|
}
|
|
&[data-state="error"] > .ok {
|
|
display: none;
|
|
}
|
|
|
|
&[data-state="error"] {
|
|
overflow-y: auto;
|
|
}
|
|
|
|
& > .ok {
|
|
display: flex;
|
|
flex-direction: row;
|
|
|
|
height: 100%;
|
|
|
|
& > rkgk-brush-preview {
|
|
flex-grow: 1;
|
|
}
|
|
}
|
|
|
|
& > .errors {
|
|
margin: 0;
|
|
padding: 4px;
|
|
color: var(--color-error);
|
|
white-space: pre-wrap;
|
|
|
|
max-height: 20em;
|
|
overflow-y: auto;
|
|
}
|
|
}
|
|
}
|
|
|
|
rkgk-brush-editor-error-exception {
|
|
& > .message {
|
|
margin: 4px 0;
|
|
}
|
|
|
|
& > .stack-trace {
|
|
margin: 0;
|
|
margin-left: 4ch;
|
|
|
|
color: var(--color-text);
|
|
|
|
& > li {
|
|
&::marker {
|
|
color: var(--color-text-dim);
|
|
}
|
|
|
|
& > button.function-name {
|
|
border: none;
|
|
border-radius: 0;
|
|
padding: 0;
|
|
background: none;
|
|
|
|
user-select: text;
|
|
|
|
font-weight: bold;
|
|
|
|
&:not(:disabled) {
|
|
text-decoration: underline;
|
|
cursor: pointer;
|
|
}
|
|
|
|
&:disabled {
|
|
opacity: 100%;
|
|
}
|
|
|
|
&.source-link {
|
|
--color-index: 0; /* set by JavaScript */
|
|
--color: oklch(40% 100% calc(var(--color-index) * 300));
|
|
|
|
color: var(--color);
|
|
|
|
&:hover {
|
|
text-decoration: none;
|
|
background-color: var(--color);
|
|
color: white;
|
|
}
|
|
}
|
|
}
|
|
|
|
& > .system {
|
|
color: var(--color-text-dim);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Brush preview */
|
|
|
|
rkgk-brush-preview {
|
|
--checkerboard-light: #f2f2f2;
|
|
--checkerboard-dark: #e1e1e1;
|
|
--checkerboard-size: 64px;
|
|
|
|
display: block;
|
|
position: relative;
|
|
|
|
background: repeating-conic-gradient(
|
|
var(--checkerboard-light) 0% 25%,
|
|
var(--checkerboard-dark) 0% 50%
|
|
)
|
|
50% 50% / var(--checkerboard-size) var(--checkerboard-size);
|
|
|
|
& > canvas {
|
|
display: block;
|
|
border-radius: 4px;
|
|
|
|
max-width: 100%;
|
|
height: auto;
|
|
|
|
/* The brush preview doesn't scale with DPI as easily as the canvas renderer does,
|
|
so instead we pixelate it. */
|
|
image-rendering: pixelated;
|
|
}
|
|
|
|
&.error {
|
|
& > canvas {
|
|
display: none;
|
|
}
|
|
|
|
&::before {
|
|
content: "(error)";
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 50%;
|
|
transform: translate(-50%, -50%);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Brush cost gauges */
|
|
|
|
rkgk-brush-cost-gauges {
|
|
--gauge-size: 20px;
|
|
|
|
display: flex;
|
|
flex-direction: row;
|
|
|
|
&.hidden {
|
|
display: none;
|
|
}
|
|
|
|
& > rkgk-brush-cost-gauge {
|
|
display: block;
|
|
width: var(--gauge-size);
|
|
height: 100%;
|
|
|
|
&.hidden {
|
|
display: none;
|
|
}
|
|
|
|
& > .full {
|
|
width: 100%;
|
|
height: 100%;
|
|
|
|
clip-path: inset(calc(100% - var(--progress)) 0 0 0);
|
|
|
|
background-color: var(--gauge-color);
|
|
}
|
|
|
|
&.code-size {
|
|
--gauge-color: var(--color-brand-blue);
|
|
}
|
|
&.fuel {
|
|
--gauge-color: #f44096;
|
|
}
|
|
&.objects {
|
|
--gauge-color: #fd9916;
|
|
}
|
|
&.memory {
|
|
--gauge-color: #5aca40;
|
|
}
|
|
}
|
|
|
|
& .icon {
|
|
background-position: 50% calc(100% - 4px);
|
|
}
|
|
}
|
|
|
|
/* Zoom indicator */
|
|
|
|
rkgk-zoom-indicator,
|
|
rkgk-zoom-indicator.rkgk-panel {
|
|
border-radius: 4px;
|
|
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
|
|
width: min-content;
|
|
|
|
overflow: clip; /* corners */
|
|
|
|
& > button {
|
|
width: 24px;
|
|
height: 24px;
|
|
}
|
|
|
|
& > p {
|
|
margin: 0;
|
|
padding: 0 4px;
|
|
line-height: 1;
|
|
width: 6ch;
|
|
|
|
font-variant-numeric: tabular-nums;
|
|
text-align: center;
|
|
}
|
|
}
|
|
|
|
/* Welcome screen */
|
|
|
|
rkgk-welcome {
|
|
& > dialog {
|
|
h3 {
|
|
margin: 0.5rem 0;
|
|
font-size: 2rem;
|
|
font-weight: bold;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Connection status dialogs */
|
|
|
|
rkgk-connection-status {
|
|
& > dialog[name="logging-in-dialog"][open],
|
|
& > dialog[name="disconnected-dialog"][open] {
|
|
border: none;
|
|
outline: none;
|
|
background: none;
|
|
|
|
display: flex;
|
|
gap: 8px;
|
|
align-items: center;
|
|
}
|
|
|
|
& > dialog[name="error-dialog"][open] {
|
|
& textarea[name="error-text"] {
|
|
box-sizing: border-box;
|
|
width: 100%;
|
|
resize: none;
|
|
border: 1px solid var(--color-panel-border);
|
|
padding: 4px;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Context menu */
|
|
|
|
rkgk-context-menu-space {
|
|
z-index: var(--z-modal);
|
|
|
|
pointer-events: none;
|
|
|
|
& > rkgk-context-menu {
|
|
pointer-events: all;
|
|
}
|
|
}
|
|
|
|
rkgk-context-menu.rkgk-panel {
|
|
width: max-content;
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
border-radius: 4px;
|
|
overflow: clip;
|
|
|
|
& > p {
|
|
margin: 0;
|
|
padding: 6px 12px;
|
|
|
|
&.small {
|
|
padding: 4px 12px;
|
|
font-size: 80%;
|
|
opacity: 75%;
|
|
}
|
|
}
|
|
|
|
& > button {
|
|
padding: 6px 12px;
|
|
|
|
border: none;
|
|
border-radius: 0;
|
|
|
|
text-align: left;
|
|
}
|
|
|
|
& > hr {
|
|
margin: 0;
|
|
width: 100%;
|
|
border-bottom: 1px solid var(--color-panel-border);
|
|
}
|
|
}
|
|
|
|
/* Menu bar */
|
|
|
|
.menu-bar {
|
|
display: flex;
|
|
align-items: center;
|
|
box-sizing: border-box;
|
|
|
|
width: 100%;
|
|
height: 28px;
|
|
|
|
margin: 0;
|
|
padding: 0;
|
|
list-style: none;
|
|
|
|
& > li {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
height: 100%;
|
|
}
|
|
|
|
& > li.icon {
|
|
display: block;
|
|
width: 28px;
|
|
height: 28px;
|
|
}
|
|
|
|
& > li > a {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
|
|
color: var(--color-text);
|
|
height: 100%;
|
|
padding: 0 8px;
|
|
text-decoration: none;
|
|
|
|
line-height: 1;
|
|
|
|
&:hover {
|
|
background-color: var(--color-shaded-background);
|
|
}
|
|
|
|
&.icon {
|
|
width: 24px;
|
|
height: 24px;
|
|
}
|
|
}
|
|
|
|
& > hr {
|
|
height: 100%;
|
|
margin: 0;
|
|
border: none;
|
|
border-right: 1px solid var(--color-panel-border);
|
|
}
|
|
}
|