rkgk/static/index.css
リキ萌 15a1bf8036 make context menus appear above resize handles
i kinda hate how shoddy this has to be
2025-06-28 23:51:52 +02:00

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);
}
}