Files
factorio-clusterio/packages/web_ui/src/style.css
T
bbassieandClaude Opus 5 71db8e57f5 Label Factorio output in the console with its log level
The Web UI console rendered server level entries as bare parsed Factorio
output, while every other level was prefixed with its name. Nothing in a
line distinguished what the game wrote from what Clusterio wrote about it,
which matters more now that both modes of the filter carry a mix of the
two.

Emit the [server] prefix for those entries as well, matching what
TerminalFormat already does for the host and controller logs, and style the
level the same bold the terminal colourises it with.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 10:58:30 +00:00

402 lines
7.1 KiB
CSS

body {
margin: 0;
}
[data-theme="compact"] p, p {
margin: 0;
}
.row-links{
cursor: pointer;
}
/* Make a table link-cell's link fill the cell width, so the whole column
width is clickable and right-click "open in new tab"-able, not just the
text. Uses display:block rather than an overlay so sibling content (e.g.
the restart-required icon) stays interactive. */
.table-link-cell a {
display: block;
}
.login-container {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.site-layout-content {
background: #141414;
padding: 24px;
margin: 0;
flex-grow: 0;
}
.site-layout {
overflow-x: clip;
}
.site-layout-content-container {
min-width: 100%;
}
.site-breadcrumb {
margin: 16px 0;
}
@media (min-width: 576px) {
.site-layout-content-container {
padding: 0 24px 24px;
}
}
@media (min-width: 768px) {
.site-layout {
overflow-x: initial;
}
.site-layout-content-container {
min-width: initial;
}
}
/* Top bar hosting the menu toggle and branding, sticky above the content. */
.site-layout-header {
position: sticky;
top: 0;
z-index: 100;
display: flex;
align-items: center;
gap: 16px;
padding-inline: 16px;
background: #001529;
}
/* Keep the sidebar fixed in place (below the header) while content scrolls. */
.site-layout-sider {
position: sticky;
top: 64px;
height: calc(100vh - 64px);
align-self: flex-start;
}
/* Snap the sider open/closed instead of animating its width — the width
transition reflowed the content area and caused styling glitches. */
.ant-layout-sider.site-layout-sider {
transition: none;
}
.page-header {
padding: 0 0 16px;
}
.site-layout-content > h2:first-child {
margin-top: 0;
}
.section-header, .page-header {
display: flex;
flex-wrap: wrap;
align-items: center;
}
.section-header {
margin-top: 16px;
margin-bottom: 8px;
}
.section-header-title, .page-header-title {
flex: auto;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.section-header-title {
font-weight: bold;
font-size: 16px;
line-height: 1.5715;
}
.page-header-title {
margin: 4px 0;
}
.section-header-extra, .page-header-extra {
margin-left: auto;
}
.error-traceback code {
display: block;
margin: 0;
background: #000;
border-color: #252525;
white-space: pre-wrap;
}
.save-list-dragger .ant-upload.ant-upload-drag {
border: none;
background: none;
height: auto;
cursor: inherit;
}
.save-list-dragger .ant-upload.ant-upload-btn {
padding: 0;
}
.save-list-table .ant-table-pagination.ant-pagination {
margin-bottom: 0;
}
.rcon-result code {
display: block;
background: #000;
border-color: #252525;
max-height: 200px;
overflow-y: auto;
white-space: pre-wrap;
animation: rcon-highlight 1s ease-out forwards;
}
@keyframes rcon-highlight {
0% { outline: 3px solid #1668dc; }
100% { outline: 3px solid transparent; }
}
/* see https://blog.eqrion.net/pin-to-bottom/ for how scroll anchors works */
.instance-console code * {
overflow-anchor: none;
}
.instance-console code .scroll-anchor {
overflow-anchor: auto;
height: 1px;
}
/* Scroll headroom above the output so short output sits at the bottom; it is
scroll content, not box padding, so it does not block dragging smaller. */
.instance-console code .console-spacer {
height: 100%;
}
.instance-console code {
display: block;
margin: 0;
background: #000;
border-color: #252525;
/* Drag-resizable (the native handle needs the scroll overflow); height is set
imperatively in LogConsole, border-box keeps padding out of offsetHeight. */
box-sizing: border-box;
height: 300px;
min-height: 100px;
resize: vertical;
overflow-y: scroll;
white-space: pre-wrap;
}
.instance-console .factorio-time {
color: #afaf1f;
}
.instance-console .factorio-filename {
color: #808080;
}
.instance-console .factorio-script {
font-weight: bold;
color: #49c33c;
}
.instance-console .factorio-verbose {
font-weight: bold;
color: #888888;
}
.instance-console .factorio-info {
font-weight: bold;
color: #4646ea;
}
.instance-console .factorio-warning {
font-weight: bold;
color: #afaf1f;
}
.instance-console .factorio-error {
font-weight: bold;
color: #ad3939;
}
.instance-console .factorio-action {
color: #afaf1f;
}
.log-verbose {
font-weight: bold;
color: #888888;
}
.log-info {
font-weight: bold;
color: #4646ea;
}
.log-audit {
font-weight: bold;
color: #49c33c;
}
.log-warn {
font-weight: bold;
color: #afaf1f;
}
.log-error {
font-weight: bold;
color: #ad3939;
}
.log-server {
font-weight: bold;
}
.log-fatal {
font-weight: bold;
background-color: #ad3939;
color: #000;
}
.config-container, .config-container .ant-tree {
background-color: #111111;
}
.config-container .ant-form-item {
margin: 0;
}
.config-container .filter-node .ant-tree-node-content-wrapper {
background: #2a1912;
}
.json-input {
font-family: monospace;
}
.factorio-icon {
display: inline-block;
vertical-align: middle;
background-repeat: no-repeat;
}
/* data-mod-pack might not be present, but we need the specificity to win over it if it is */
.factorio-icon:is([data-mod-pack],*)[data-unknown="true"] {
background: url("./images/unknown-item.png");
height: 32px;
width: 32px;
}
.code > code {
display: block;
}
/*
* Render codeblock with options for syntax highlighting
* https://user-images.githubusercontent.com/6792749/152066701-21420461-710b-4fae-a80a-89ef90a0b18f.png
*/
.codeblock {
background-color: black;
padding: 8px;
padding-right: 5em;
margin-bottom: 1em;
min-height: 2.5em;
line-height: 18px;
font-family: Courier;
position: relative;
}
.codeblock .highlight {
color: yellow;
}
.codeblock .copy-button {
position: absolute;
top: 8px;
right: 8px;
}
.ant-descriptions-bordered.borderless > .ant-descriptions-view {
border: none;
}
div.ant-table tr.no-expanded-padding > td,
div.ant-table.ant-table-small .ant-table-tbody > tr.no-expanded-padding > td {
padding: 0;
}
.ant-form-item.changed,
input.ant-input.changed,
textarea.ant-input.changed,
tr.ant-table-row.changed > td {
background: #2a1912;
}
.ant-table-tbody > tr.ant-table-row.changed:hover > td,
.ant-table-tbody > tr.changed > td.ant-table-cell-row-hover
tr.ant-table-row.deleted > td {
background: #3a2922;
}
tr.ant-table-row.deleted {
color: rgba(255, 255, 255, 0.45);
background: #340c08;
text-decoration: line-through;
}
.ant-table-tbody > tr.ant-table-row.deleted:hover > td,
.ant-table-tbody > tr.deleted > td.ant-table-cell-row-hover
tr.ant-table-row.deleted {
background: #441c18;
}
.sticky-notice {
position: sticky;
inset: auto auto 24px auto;
background: #1f1f1f;
padding: 24px;
width: auto;
margin: 16px auto 0;
box-shadow:
0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 9px 28px 8px rgba(0, 0, 0, 0.05);
border-radius: 8px;
max-width: 384px;
}
/**
* Tri-state segmented control:
* represents include, exclude, or no filter
*/
.seg-yes {
color: #389e0d;
}
.seg-no {
color: #cf1322;
}
.ant-segmented-item-selected.seg-yes {
background-color: #389e0d !important;
color: white !important;
}
.ant-segmented-item-selected.seg-no {
background-color: #cf1322 !important;
color: white !important;
}
.seg-yes:hover {
background-color: #306317;
}
.seg-no:hover {
background-color: #7a2e2f;
}