rkgk/static/index.css
liquidev 39886291cf HiDPI support
the main canvas is now DPI-aware; it should no longer be pixelated on 4k
this couldn't be done for the brush preview, so it's just kinda pixelated
also fixed the horrendous scrollbar that could appear on HiDPI for some reason
2025-05-25 21:26:21 +02:00

527 lines
11 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. */
/* 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 */
box-sizing: border-box;
padding: 16px;
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;
}
& > .right {
grid-column: right / right;
min-height: 0;
display: grid;
grid-template-rows: minmax(0, min-content);
grid-template-columns: [floating] max-content [resize] min-content [docked] auto;
padding-left: 16px;
pointer-events: none;
& > * {
min-width: 0;
min-height: 0;
}
& > rkgk-resize-handle {
pointer-events: auto;
}
& > .docked > rkgk-brush-editor {
max-height: 100%;
pointer-events: auto;
}
& > .floating {
display: flex;
flex-direction: column;
gap: 12px;
& > rkgk-brush-preview {
width: 128px;
height: 128px;
pointer-events: auto;
}
& > rkgk-brush-cost-gauges {
width: 100%;
pointer-events: auto;
}
}
}
}
& > 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);
display: flex;
align-items: center;
justify-content: center;
}
}
/* Resize handle */
rkgk-resize-handle {
&[data-direction="vertical"] {
display: block;
width: 16px;
height: 100%;
cursor: col-resize;
& > .visual {
width: 2px;
height: 100%;
background-color: var(--color-brand-blue);
margin: 0 auto;
opacity: 0%;
}
&:hover > .visual,
&.dragging > .visual {
opacity: 100%;
}
}
}
/* 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;
}
}
}
/* Code editor */
rkgk-code-editor {
--gutter-width: 2.75em;
display: block;
position: relative;
width: 100%;
overflow: auto;
& > .layer {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 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 {
user-select: none;
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);
}
}
}
& > textarea {
display: block;
width: calc(100% - var(--gutter-width));
margin: 0;
margin-left: var(--gutter-width);
padding: 0;
box-sizing: border-box;
overflow: hidden;
resize: none;
white-space: pre-wrap;
border: none;
&:focus {
outline: none;
}
}
&:has(textarea:focus) {
outline: 1px solid var(--color-brand-blue);
outline-offset: 4px;
}
}
/* Brush editor */
rkgk-brush-editor.rkgk-panel {
padding: 12px;
display: flex;
flex-direction: column;
gap: 4px;
position: relative;
& > .text-area {
display: block;
width: 100%;
margin: 0;
resize: none;
white-space: pre-wrap;
border: none;
overflow: hidden;
box-sizing: border-box;
}
& > .errors:empty,
& > .error-header:empty {
display: none;
}
& > .error-header {
margin: 0;
margin-top: 0.5em;
font-size: 1rem;
color: var(--color-error);
}
& > .errors {
margin: 0;
color: var(--color-error);
white-space: pre-wrap;
}
}
/* 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);
border-radius: 4px;
& > canvas {
border-radius: 4px;
/* 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,
rkgk-brush-cost-gauges.rkgk-panel {
--gauge-size: 20px;
height: var(--gauge-size);
border-radius: 4px;
display: flex;
flex-direction: row;
overflow: clip; /* clip corners */
& > rkgk-brush-cost-gauge {
display: block;
height: var(--gauge-size);
flex-grow: 1;
& > .full {
width: 100%;
height: 100%;
clip-path: xywh(0 0 var(--progress) 100%);
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;
}
}
}
/* 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;
}
}
}
/* Menu bar */
.menu-bar {
--border-radius: 4px;
display: flex;
align-items: center;
box-sizing: border-box;
width: fit-content;
height: 24px;
border-radius: var(--border-radius);
& > a {
display: block;
color: var(--color-text);
padding: 4px 8px;
text-decoration: none;
line-height: 1;
&:hover {
background-color: var(--color-shaded-background);
}
&.icon {
width: 24px;
height: 24px;
}
&:first-child {
border-top-left-radius: var(--border-radius);
border-bottom-left-radius: var(--border-radius);
}
&:last-child {
border-top-right-radius: var(--border-radius);
border-bottom-right-radius: var(--border-radius);
}
}
& > hr {
height: 100%;
margin: 0;
border: none;
border-right: 1px solid var(--color-panel-border);
}
}