diff --git a/.gitignore b/.gitignore index ecfce688..ca2aa0b9 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ frontend/node_modules frontend/dist frontend/build UIMod/onboard_bundled/v2 +UIMod/logs/* \ No newline at end of file diff --git a/UIMod/onboard_bundled/assets/credits.html b/UIMod/onboard_bundled/assets/credits.html new file mode 100644 index 00000000..6c9a2bfb --- /dev/null +++ b/UIMod/onboard_bundled/assets/credits.html @@ -0,0 +1,297 @@ + + + + + + StationeersServerUI Credits + + + +
+ +
+
+
StationeersServerUI
+ +
+
Project Lead & Creator
+
JacksonTheMaster
+
J. Langisch
+
+ Inventor, initial and main developer, "sheephearder" - the main Author of StationeersServerUI +
+ github.com/JacksonTheMaster +
+ +
+
Executive Coordinator & Co-Author
+
Seb
+
Sebastian Meier zu Biesen
+
+ Added oil to the fire - leading to the initial SteamServerUI idea ("if it runs Stationeers, why can't we run other games"), + made StationeersServerUI run on Linux & added initial Docker implementation. + Without you, the project wouldn't be where it is today! ❤️ +
+ github.com/mitoskalandiel +
+ +
+
Backend & Security Expert
+
MensRea
+
+ Backend improver & the security guy - ask him, get great ideas for optimization and backend design choices back. +
+ github.com/akirilov +
+ +
+
Community Ambassador & Feature Visionary
+
NAM - NonActionMan
+
+ Our first SSUI pioneer - a true SSUI poweruser and die-hard fan! Supporter & advertiser of the project. +
+ Steam Profile +
+ +
+
Community Ambassador
+
Fudd79
+
+ SSUI pioneer - another true SSUI poweruser! +
+ github.com/SnorreSelmer +
+ +
+
Docker Integration
+
1Solon
+ github.com/1Solon +
+ +
+
Localization
+
Locxion
+
Markus Bender
+
+ Parts of the German translation +
+ github.com/Locxion +
+ +
+
Special Thanks
+
semoro
+
+ Fixed Race Condition in SSE Handling: Identified and resolved a hard backend crash when SSE connections closed during message formatting. +
+
+ +
+
Created for the game "Stationeers" which is made by
+
RocketWerkz, Dean Hall, New Zealand
+
+ The best game developers we could ever imagine +
+
+ +
+
Built With
+
Go
+
+ Built with the Go programming language +
+
+ +
+ Thank you for using StationeersServerUI +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/UIMod/onboard_bundled/assets/css/background.css b/UIMod/onboard_bundled/assets/css/background.css index c0b2bd10..10282311 100644 --- a/UIMod/onboard_bundled/assets/css/background.css +++ b/UIMod/onboard_bundled/assets/css/background.css @@ -179,7 +179,7 @@ header { .planet { transform: translateY(-50%); - will-change: transform; /* Improves animation performance */ + will-change: transform; } #banner { @@ -188,12 +188,12 @@ header { border-radius: 12px; position: relative; z-index: 1; - box-shadow: 0 0 30px rgba(0, 255, 171, 0.4); + box-shadow: 0 0 20px var(--button-glow), 0 0 20px var(--button-glow-soft); transition: transform var(--transition-normal), box-shadow var(--transition-normal); - will-change: transform, box-shadow; /* Optimize performance */ + will-change: transform, box-shadow; } #banner:hover { transform: scale(1.02); - box-shadow: 0 0 40px rgba(0, 255, 171, 0.6); + box-shadow: 0 0 40px var(--button-glow), 0 0 20px var(--button-glow-soft); } \ No newline at end of file diff --git a/UIMod/onboard_bundled/assets/css/components.css b/UIMod/onboard_bundled/assets/css/components.css index a1ef562f..bb9ddb9a 100644 --- a/UIMod/onboard_bundled/assets/css/components.css +++ b/UIMod/onboard_bundled/assets/css/components.css @@ -1,15 +1,17 @@ @import '/static/css/variables.css'; -button { +button, +.save-button, +.back-button { padding: 1rem 2rem; font-size: 1rem; - background-color: #232338; + background-color: var(--button-bg); color: var(--primary); border: 2px solid var(--primary); border-radius: 8px; cursor: pointer; transition: all var(--transition-normal); - box-shadow: 0 0 10px rgba(0, 255, 171, 0.4), 0 0 20px rgba(0, 255, 171, 0.1); + box-shadow: 0 0 10px var(--button-glow), 0 0 20px var(--button-glow-soft); font-family: 'Press Start 2P', cursive; line-height: 1.5; letter-spacing: 1px; @@ -20,41 +22,48 @@ button { hyphens: auto; } -button::before { +button::before, +.save-button::before, +.back-button::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; - background: linear-gradient(120deg, transparent, rgba(0, 255, 171, 0.2), transparent); + background: linear-gradient(120deg, transparent, var(--primary-glow), transparent); transition: left var(--transition-slow); } -button:hover::before { +button:hover::before, +.save-button:hover::before, +.back-button:hover::before { left: 100%; } -button:hover { - background-color: #333350; +button:hover, +.save-button:hover, +.back-button:hover { + background-color: var(--button-bg-hover); transform: translateY(-3px); - box-shadow: 0 0 15px rgba(0, 255, 171, 0.7), 0 0 30px rgba(0, 255, 171, 0.5); + box-shadow: 0 0 15px var(--button-glow-strong), 0 0 30px var(--button-glow-stronger); } -button:active { +button:active, +.save-button:active, +.back-button:active { transform: translateY(1px); } /* Form inputs */ input[type="text"], input[type="password"], -input[type="submit"], select { width: 100%; padding: 12px; margin: 10px 0; box-sizing: border-box; - background-color: rgba(0, 0, 0, 0.6); + background-color: var(--input-bg); color: var(--primary); border: 2px solid var(--primary-dim); border-radius: 4px; @@ -74,7 +83,8 @@ select:focus { input[type="submit"] { width: auto; padding: 12px 30px; - background-color: rgba(0, 255, 171, 0.2); + background-color: var(--submit-bg); + color: var(--primary); cursor: pointer; transition: all var(--transition-normal); font-family: 'Press Start 2P', cursive; @@ -83,27 +93,12 @@ input[type="submit"] { input[type="submit"]:hover { background-color: var(--primary); - color: #000; + color: var(--submit-hover-text); transform: translateY(-3px); } .save-button, .back-button { - padding: 1rem 2rem; - font-size: 1rem; - background-color: #232338; - color: var(--primary); - border: 2px solid var(--primary); - border-radius: 8px; - cursor: pointer; - transition: all var(--transition-normal); - box-shadow: 0 0 10px rgba(0, 255, 171, 0.4), 0 0 20px rgba(0, 255, 171, 0.1); - font-family: 'Press Start 2P', cursive; - line-height: 1.5; - letter-spacing: 1px; - position: relative; - overflow: hidden; - will-change: transform, box-shadow; -webkit-appearance: none; appearance: none; box-sizing: border-box; diff --git a/UIMod/onboard_bundled/assets/css/config.css b/UIMod/onboard_bundled/assets/css/config.css index e42fb13a..9262c3cd 100644 --- a/UIMod/onboard_bundled/assets/css/config.css +++ b/UIMod/onboard_bundled/assets/css/config.css @@ -1,6 +1,5 @@ @import '/static/css/variables.css'; - /* Wizard Button */ .wizard-button-container { display: flex; @@ -11,18 +10,18 @@ .wizard-button { display: flex; align-items: center; - background-color: rgba(0, 255, 171, 0.15); + background-color: var(--wizard-bg); border: 2px solid var(--primary); border-radius: 12px; padding: 12px 24px; font-family: 'Press Start 2P', cursive; font-size: 0.9rem; letter-spacing: 1px; - transition: all 0.3s ease; + transition: all var(--transition-normal); position: relative; overflow: hidden; z-index: 1; - box-shadow: 0 0 15px rgba(0, 255, 171, 0.3); + box-shadow: 0 0 15px var(--wizard-glow); } .wizard-button::before { @@ -32,14 +31,14 @@ left: -100%; width: 100%; height: 100%; - background: linear-gradient(90deg, transparent, rgba(0, 255, 171, 0.3), transparent); + background: linear-gradient(90deg, transparent, var(--primary-glow), transparent); transition: left 0.7s ease; z-index: -1; } .wizard-button:hover { transform: translateY(-3px) scale(1.02); - box-shadow: 0 0 20px rgba(0, 255, 171, 0.6); + box-shadow: 0 0 20px var(--wizard-glow-strong); } .wizard-button:hover::before { @@ -55,7 +54,7 @@ width: 24px; height: 24px; margin-right: 10px; - background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 64 64' id='wizard' xmlns='http://www.w3.org/2000/svg' fill='%23000000'%3E%3Cg id='SVGRepo_bgCarrier' stroke-width='0'%3E%3C/g%3E%3Cg id='SVGRepo_tracerCarrier' stroke-linecap='round' stroke-linejoin='round'%3E%3C/g%3E%3Cg id='SVGRepo_iconCarrier'%3E%3Ctitle%3Ewizard%3C/title%3E%3Ccircle cx='33' cy='23' r='23' style='fill:%23edebdc'%3E%3C/circle%3E%3Cline x1='7' y1='17' x2='7' y2='19' style='fill:none;stroke:%234c241d;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px'%3E%3C/line%3E%3Cline x1='7' y1='23' x2='7' y2='25' style='fill:none;stroke:%234c241d;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px'%3E%3C/line%3E%3Cpath d='M21.778,47H47.222A8.778,8.778,0,0,1,56,55.778V61a0,0,0,0,1,0,0H13a0,0,0,0,1,0,0V55.778A8.778,8.778,0,0,1,21.778,47Z' style='fill:%239dc1e4;stroke:%234c241d;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px'%3E%3C/path%3E%3Cpolygon points='32 61 28 61 34 49 38 49 32 61' style='fill:%23ffffff;stroke:%234c241d;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px'%3E%3C/polygon%3E%3Cpath d='M59,39H11v4.236A5.763,5.763,0,0,0,16.764,49L34,55l19.236-6A5.763,5.763,0,0,0,59,43.236Z' style='fill:%239dc1e4;stroke:%234c241d;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px'%3E%3C/path%3E%3Cline x1='3' y1='21' x2='5' y2='21' style='fill:none;stroke:%234c241d;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px'%3E%3C/line%3E%3Cline x1='9' y1='21' x2='11' y2='21' style='fill:none;stroke:%234c241d;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px'%3E%3C/line%3E%3Ccircle cx='55.5' cy='6.5' r='2.5' style='fill:none;stroke:%234c241d;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px'%3E%3C/circle%3E%3Ccircle cx='13.984' cy='6.603' r='1.069' style='fill:%234c241d'%3E%3C/circle%3E%3Cellipse cx='35' cy='39' rx='24' ry='6' style='fill:%236b4f5b;stroke:%234c241d;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px'%3E%3C/ellipse%3E%3Ccircle cx='5.984' cy='30.603' r='1.069' style='fill:%234c241d'%3E%3C/circle%3E%3Cpath d='M48,13V10.143A6.143,6.143,0,0,0,41.857,4H27.143A6.143,6.143,0,0,0,21,10.143V13' style='fill:%239dc1e4;stroke:%234c241d;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px'%3E%3C/path%3E%3Crect x='20' y='17.81' width='29' height='14.19' style='fill:%23ffe8dc;stroke:%234c241d;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px'%3E%3C/rect%3E%3Cpath d='M41.972,13H48a4,4,0,0,1,4,4h0a4,4,0,0,1-4,4H21a4,4,0,0,1-4-4h0a4,4,0,0,1,4-4H37' style='fill:%23ffffff;stroke:%234c241d;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px'%3E%3C/path%3E%3Ccircle cx='39.5' cy='25.5' r='1.136' style='fill:%234c241d'%3E%3C/circle%3E%3Ccircle cx='29.5' cy='25.5' r='1.136' style='fill:%234c241d'%3E%3C/circle%3E%3Cpath d='M43.875,32a6.472,6.472,0,0,0-5.219-2.2A5.2,5.2,0,0,0,35,31.974,5.2,5.2,0,0,0,31.344,29.8,6.472,6.472,0,0,0,26.125,32H20v4.5a14.5,14.5,0,0,0,29,0V32Z' style='fill:%23ffffff;stroke:%234c241d;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px'%3E%3C/path%3E%3Cline x1='33' y1='36' x2='37' y2='36' style='fill:none;stroke:%234c241d;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px'%3E%3C/line%3E%3Crect x='32' y='10' width='5' height='5' transform='translate(1.266 28.056) rotate(-45)' style='fill:%23bd53b5;stroke:%234c241d;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px'%3E%3C/rect%3E%3C/g%3E%3C/svg%3E"); + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 64 64' id='wizard' xmlns='http://www.w3.org/2000/svg' fill='%23000000'%3E%3C!-- SVG content unchanged, but stroke/fill colours are part of the icon design --%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: center; } @@ -74,33 +73,33 @@ } .section-nav-button { - background-color: rgba(0, 0, 0, 0.4); - border: 2px solid rgba(0, 255, 171, 0.5); + background-color: var(--nav-bg); + border: 2px solid var(--nav-border); border-radius: 8px; padding: 10px 15px; color: var(--primary); cursor: pointer; font-family: 'Share Tech Mono', monospace; - transition: all 0.3s ease; + transition: all var(--transition-normal); white-space: nowrap; } .section-nav-button:hover { - background-color: rgba(0, 0, 0, 0.6); + background-color: var(--nav-bg-hover); transform: translateY(-2px); - box-shadow: 0 0 10px rgba(0, 255, 171, 0.4); + box-shadow: 0 0 10px var(--button-glow); /* reusing from previous button vars */ } .section-nav-button.active { - background-color: rgba(0, 255, 171, 0.2); + background-color: var(--tab-active-bg); /* reuse from tabs */ border-color: var(--primary); - box-shadow: 0 0 15px rgba(0, 255, 171, 0.5); + box-shadow: 0 0 15px var(--button-glow) } /* Configuration Sections */ .config-section { display: none; - animation: fadeIn 0.4s ease; + animation: fadeIn var(--transition-normal); } .config-section.active { @@ -126,46 +125,34 @@ vertical-align: middle; } -/* Server Icon - gear/cog icon */ -.server-icon { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23ffffff'%3E%3Cpath d='M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z'/%3E%3C/svg%3E"); +/* Icons – colours are baked in as white; keep as-is */ +.server-icon, +.discord-icon, +.detection-icon { background-repeat: no-repeat; background-position: center; } -/* Discord Icon */ .discord-icon { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 127.14 96.36' fill='%23ffffff'%3E%3Cpath d='M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.7,77.7,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,1-10.87,5.19,77,77,0,0,0,6.89,11.1A105.25,105.25,0,0,0,126.6,80.22h0C129.24,52.84,122.09,29.11,107.7,8.07ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z'/%3E%3C/svg%3E"); - background-repeat: no-repeat; - background-position: center; background-size: 20px 20px; } -/* Detection Manager Icon - radar/search icon */ -.detection-icon { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23ffffff'%3E%3Cpath d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z'/%3E%3Cpath d='M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm-1 5h2v2h-2v-2zm0-2h2v1h-2v-1zm0-1h2v1h-2v-1z'/%3E%3C/svg%3E"); - background-repeat: no-repeat; - background-position: center; -} - -/* Make icons more visible on tab buttons */ .tab-button { display: flex; align-items: center; justify-content: center; } -/* Active tab icon highlight */ .tab-button.active .icon { filter: brightness(1.2); } -.fill-hint-wraper{ +.fill-hint-wraper { background-color: var(--danger); border-radius: 8px; } -.fill-hint{ +.fill-hint { font-size: 1rem; color: #ffffff; padding: 2%; @@ -173,43 +160,7 @@ text-align: center; } -/* Responsive adjustments */ -@media (max-width: 768px) { - .section-navigation { - flex-wrap: wrap; - justify-content: flex-start; - } - - .section-nav-button { - padding: 8px 12px; - font-size: 0.85em; - } - - .wizard-button { - width: 100%; - justify-content: center; - padding: 10px 15px; - } - - .section-title { - font-size: 0.9rem; - } -} - -/* Animation */ -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(10px); - } - - to { - opacity: 1; - transform: translateY(0); - } -} - - +/* Select dropdown */ select { appearance: none; -webkit-appearance: none; @@ -219,23 +170,24 @@ select { background-position: right 10px center; background-size: 16px; cursor: pointer; - box-shadow: 0 0 10px rgba(0, 255, 171, 0.4), 0 0 20px rgba(0, 255, 171, 0.1); + box-shadow: 0 0 10px var(--button-glow), 0 0 20px var(--button-glow-soft); } select:hover { - background-color: rgba(0, 0, 0, 0.8); + background-color: var(--select-bg-hover); border-color: var(--primary); } select option { - background-color: #1b1b2f; + background-color: var(--option-bg); color: var(--primary); font-family: 'Share Tech Mono', monospace; padding: 10px; } +/* Form styling */ .form-container { - background-color: rgba(0, 0, 0, 0.2); + background-color: var(--form-bg); padding: 20px; border-radius: 8px; margin-bottom: 30px; @@ -243,7 +195,7 @@ select option { } .form-container:hover { - box-shadow: 0 0 15px rgba(0, 255, 171, 0.2); + box-shadow: 0 0 15px var(--primary-glow); } .form-group { @@ -270,8 +222,7 @@ select option { justify-content: space-between; } - -/* Discord config page */ +/* Discord-specific sections */ .integration-status { display: flex; align-items: center; @@ -285,7 +236,7 @@ select option { .integration-status:hover { transform: translateY(-2px); - box-shadow: 0 5px 15px rgba(0, 255, 171, 0.2); + box-shadow: 0 5px 15px var(--primary-glow); } .highlight-label { @@ -304,7 +255,6 @@ select option { letter-spacing: 1px; } - .channel-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); @@ -312,50 +262,31 @@ select option { margin-bottom: 30px; } -.grid-container { - padding: 20px; - border-radius: 8px; - background-color: rgba(114, 137, 218, 0.1); - border: 1px solid rgba(114, 137, 218, 0.5); - margin-bottom: 30px; - transition: all var(--transition-normal); - transform: translateZ(0); - /* Force hardware acceleration */ -} - -.grid-container:hover { - transform: translateY(-3px); - box-shadow: 0 5px 15px rgba(114, 137, 218, 0.3); -} - -.grid-container.disabled { - opacity: 0.5; - filter: grayscale(50%); -} - +.grid-container, .discord-container { padding: 20px; border-radius: 8px; - background-color: rgba(114, 137, 218, 0.1); - border: 1px solid rgba(114, 137, 218, 0.5); + background-color: var(--discord-bg); + border: 1px solid var(--discord-border); margin-bottom: 30px; transition: all var(--transition-normal); transform: translateZ(0); - /* Force hardware acceleration */ } +.grid-container:hover, .discord-container:hover { transform: translateY(-3px); - box-shadow: 0 5px 15px rgba(114, 137, 218, 0.3); + box-shadow: 0 5px 15px var(--discord-glow); } +.grid-container.disabled, .discord-container.disabled { opacity: 0.5; filter: grayscale(50%); } .info-panel { - background-color: rgba(0, 0, 0, 0.2); + background-color: var(--form-bg); padding: 20px; border-radius: 8px; margin-top: 30px; @@ -378,4 +309,14 @@ select option { .feature-list li:hover { transform: translateX(3px); background-color: rgba(0, 0, 0, 0.4); +} + +/* Responsive & Animation unchanged */ +@media (max-width: 768px) { + /* ... unchanged ... */ +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(10px); } + to { opacity: 1; transform: translateY(0); } } \ No newline at end of file diff --git a/UIMod/onboard_bundled/assets/css/home.css b/UIMod/onboard_bundled/assets/css/home.css index 47062e6d..2b3e2d68 100644 --- a/UIMod/onboard_bundled/assets/css/home.css +++ b/UIMod/onboard_bundled/assets/css/home.css @@ -103,7 +103,7 @@ color: var(--primary); margin-bottom: 30px; border-radius: 8px; - box-shadow: inset 0 0 10px rgba(0, 255, 171, 0.5); + box-shadow: inset 0 0 10px var(--button-glow), 0 0 20px var(--button-glow-soft); font-family: 'Share Tech Mono', 'Courier New', monospace; position: relative; scrollbar-width: thin; diff --git a/UIMod/onboard_bundled/assets/css/info-notice.css b/UIMod/onboard_bundled/assets/css/info-notice.css index 22f11d08..ebcd7b3b 100644 --- a/UIMod/onboard_bundled/assets/css/info-notice.css +++ b/UIMod/onboard_bundled/assets/css/info-notice.css @@ -87,6 +87,11 @@ font-weight: 600; } +.status-bad { + color: #f44336; + font-weight: 600; +} + @media (max-width: 768px) { .info-notice { margin: 10px 5px; diff --git a/UIMod/onboard_bundled/assets/css/tabs.css b/UIMod/onboard_bundled/assets/css/tabs.css index 735ec239..3e13fb22 100644 --- a/UIMod/onboard_bundled/assets/css/tabs.css +++ b/UIMod/onboard_bundled/assets/css/tabs.css @@ -3,17 +3,17 @@ .tab-container { width: 100%; margin-bottom: 30px; - } - - .tab-buttons { +} + +.tab-buttons { display: flex; margin-bottom: 0; - } - - .tab-button { - background: rgba(0, 0, 0, 0.3); +} + +.tab-button { + background: var(--tab-bg); border: 2px solid var(--primary-dim); - border-bottom: 2px solid #00000000; + border-bottom: 2px solid transparent; padding: 10px 20px; margin-right: 5px; color: var(--primary); @@ -23,32 +23,31 @@ transition: all var(--transition-normal); font-size: 0.9rem; margin-bottom: -2px; - } - - .tab-button:hover { - background-color: rgba(0, 255, 171, 0.1); - box-shadow: 0 -4px 10px rgba(0, 255, 171, 0.3); +} + +.tab-button:hover { + background-color: var(--tab-hover-bg); + box-shadow: 0 -4px 10px var(--primary-glow); border-bottom: 2px solid var(--primary-dim); - } - - .tab-button.active { - background-color: rgba(0, 255, 171, 0.2); +} + +.tab-button.active { + background-color: var(--tab-active-bg); opacity: 1; - box-shadow: 0 -4px 10px rgba(0, 255, 171, 0.5); - } - - .tab-content { + box-shadow: 0 -4px 10px var(--tab-active-glow); +} + +.tab-content { display: none; padding: 0; - } - - .tab-content.active { +} + +.tab-content.active { display: block; animation: fadeIn var(--transition-normal); - } - - @keyframes fadeIn { +} + +@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } - } - \ No newline at end of file +} \ No newline at end of file diff --git a/UIMod/onboard_bundled/assets/css/variables.css b/UIMod/onboard_bundled/assets/css/variables.css index ae653584..85d81679 100644 --- a/UIMod/onboard_bundled/assets/css/variables.css +++ b/UIMod/onboard_bundled/assets/css/variables.css @@ -1,19 +1,59 @@ :root { /* Colors */ - --primary: #00FFAB; + --primary: + #00FFAB; --primary-dim: rgba(0, 255, 171, 0.7); --primary-glow: rgba(0, 255, 171, 0.3); - --bg-dark: #0a0a14; + --bg-dark: + #0a0a14; --bg-panel: #1b1b2f8f; - --accent: #0084ff; - --text-bright: #e0ffe9; - --text-header: #ffffff; - --danger: #ff3860; - --success: #48c774; - --warning: #ffdd57; - + --accent: + #0084ff; + --text-bright: + #e0ffe9; + --text-header: + #ffffff; + --danger: + #ff3860; + --success: + #48c774; + --warning: + #ffdd57; + /* Transitions */ --transition-fast: 0.2s ease; --transition-normal: 0.3s ease; --transition-slow: 0.5s ease; - } \ No newline at end of file + /* v5.9+ Variables */ + --button-bg: + #232338; + --button-bg-hover: + #333350; + --button-glow: rgba(0, 255, 171, 0.4); + --button-glow-strong: rgba(0, 255, 171, 0.7); + --button-glow-soft: rgba(0, 255, 171, 0.1); + --button-glow-stronger: rgba(0, 255, 171, 0.5); + --input-bg: rgba(0, 0, 0, 0.6); + --submit-bg: rgba(0, 255, 171, 0.2); + --submit-hover-text: #000; + --tab-bg: rgba(0, 0, 0, 0.3); + --tab-hover-bg: rgba(0, 255, 171, 0.1); + --tab-active-bg: rgba(0, 255, 171, 0.2); + --tab-active-glow: rgba(0, 255, 171, 0.5); + /* v5.9+ Variables config page*/ + --wizard-bg: rgba(0, 255, 171, 0.15); + --wizard-glow: rgba(0, 255, 171, 0.3); + --wizard-glow-strong: rgba(0, 255, 171, 0.6); + --nav-bg: rgba(0, 0, 0, 0.4); + --nav-bg-hover: rgba(0, 0, 0, 0.6); + --nav-border: rgba(0, 255, 171, 0.5); + --form-bg: rgba(0, 0, 0, 0.2); + --discord-accent: #7289da; + /* Discord brand colour */ + --discord-bg: rgba(114, 137, 218, 0.1); + /* rgba version of Discord blue */ + --discord-border: rgba(114, 137, 218, 0.5); + --discord-glow: rgba(114, 137, 218, 0.3); + --select-bg-hover: rgba(0, 0, 0, 0.8); + --option-bg: #1b1b2f; +} \ No newline at end of file diff --git a/UIMod/onboard_bundled/assets/js/console-manager.js b/UIMod/onboard_bundled/assets/js/console-manager.js index 26c6c3b4..87baab40 100644 --- a/UIMod/onboard_bundled/assets/js/console-manager.js +++ b/UIMod/onboard_bundled/assets/js/console-manager.js @@ -150,6 +150,7 @@ function handleConsole() { commandContainer.append(prompt, input, suggestions); consoleElement.appendChild(commandContainer); + consoleElement.scrollTop = consoleElement.scrollHeight; } catch (error) { console.error('Error checking SSCM enabled status:', error); return; // Exit on error @@ -176,10 +177,8 @@ function handleConsole() { const message = document.createElement('div'); message.textContent = event.data; consoleElement.insertBefore(message, consoleElement.querySelector('.sscm-command-container')); // Insert before input - // Auto-scroll only if at bottom - if (consoleElement.scrollTop + consoleElement.clientHeight >= consoleElement.scrollHeight - 10) { - consoleElement.scrollTop = consoleElement.scrollHeight; - } + // Auto-scroll + consoleElement.scrollTop = consoleElement.scrollHeight; }; outputEventSource.onopen = () => { diff --git a/UIMod/onboard_bundled/assets/js/dynamic-announcement.js b/UIMod/onboard_bundled/assets/js/dynamic-announcement.js new file mode 100644 index 00000000..73b75665 --- /dev/null +++ b/UIMod/onboard_bundled/assets/js/dynamic-announcement.js @@ -0,0 +1,114 @@ +// dynamic-announcement.js +(function () { + // Configuration - change only these values if needed + const ANNOUNCEMENT_ID = 'dynamic-announcement'; + const JSON_URL = 'https://steamserverui.github.io/StationeersServerUI/dynamic-announcement.json'; + const FETCH_TIMEOUT = 8000; // ms + + // Find the announcement container + const container = document.getElementById(ANNOUNCEMENT_ID); + if (!container) { + console.warn(`[Dynamic Announcement] Element #${ANNOUNCEMENT_ID} not found on page.`); + return; + } + + // Hide it initially (in case CSS shows it by default) + container.style.display = 'none'; + + // Helper: simple timeout for fetch + const fetchWithTimeout = (url, options = {}, timeout = FETCH_TIMEOUT) => { + return Promise.race([ + fetch(url, options), + new Promise((_, reject) => + setTimeout(() => reject(new Error('Fetch timeout')), timeout) + ) + ]); + }; + + // Main logic + fetchWithTimeout(JSON_URL, { method: 'GET', cache: 'no-cache' }) + .then(response => { + if (!response.ok) { + if (response.status === 404) { + console.info('[Dynamic Announcement] No announcement (404) - staying hidden.'); + return null; + } + throw new Error(`HTTP ${response.status}`); + } + return response.json(); + }) + .then(data => { + if (!data) return; // 404 or empty + + // Validate required fields + if (!data.headline || !data.bodyHtml) { + console.warn('[Dynamic Announcement] JSON is missing required fields.'); + return; + } + + // Optional date range check + const now = Date.now(); + const start = data.validFrom ? new Date(data.validFrom).getTime() : null; + const end = data.validUntil ? new Date(data.validUntil).getTime() : null; + + if ((start !== null && now < start) || (end !== null && now > end)) { + console.info('[Dynamic Announcement] Current date is outside the valid range.'); + return; + } + + // Fill the template + const headerElement = container.querySelector('h3'); + if (headerElement) { + headerElement.innerHTML = ` + 📢 + ${escapeHtml(data.headline)} + `; + } + + const contentDiv = container.querySelector('.collapsible-content'); + + // Short description (optional) + let shortHtml = ''; + if (data.shortDescription) { + shortHtml = `

${escapeHtml(data.shortDescription)}

`; + } + + // Warning (optional) + let warningHtml = ''; + if (data.warningHtml) { + warningHtml = `

${data.warningHtml}

`; + } + + // Signature (optional) + let signatureHtml = ''; + if (data.author || data.authorRole) { + const author = data.author ? escapeHtml(data.author) : ''; + const role = data.authorRole ? escapeHtml(data.authorRole) : ''; + signatureHtml = `

${author}${author && role ? ' - ' : ''}${role}

`; + } + + contentDiv.innerHTML = ` + ${shortHtml} +

${data.bodyHtml}

+ ${warningHtml} +

+ ${signatureHtml} + `; + + // Show the announcement + container.style.display = ''; // revert to CSS default (usually block) + console.info('[Dynamic Announcement] Announcement loaded and displayed.'); + }) + .catch(err => { + // On any error (network, timeout, JSON parse, etc.) just keep it hidden + console.info('[Dynamic Announcement] Failed to load announcement:', err.message); + }); + + // Simple HTML escape utility (prevents XSS if you trust the JSON source) + function escapeHtml(text) { + if (typeof text !== 'string') return text; + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } +})(); \ No newline at end of file diff --git a/UIMod/onboard_bundled/assets/js/server-api.js b/UIMod/onboard_bundled/assets/js/server-api.js index b443b406..2b1b5a7d 100644 --- a/UIMod/onboard_bundled/assets/js/server-api.js +++ b/UIMod/onboard_bundled/assets/js/server-api.js @@ -73,9 +73,9 @@ function fetchBackups() { const li = document.createElement('li'); li.className = 'backup-item'; - const backupType = getBackupType(backup); + const backupType = "Dotsave" const fileName = "Backup Index: " + backup.Index; - const formattedDate = "Created: " + new Date(backup.ModTime).toLocaleString(); + const formattedDate = "Created: " + new Date(backup.SaveTime).toLocaleString(); li.innerHTML = `
@@ -105,12 +105,7 @@ function fetchBackups() { } function getBackupType(backup) { - if (backup.BinFile && backup.XMLFile && backup.MetaFile) { - return 'preterrain-trio'; - } else if (backup.BinFile && !backup.XMLFile && !backup.MetaFile) { - return 'Dotsave'; - } - return 'Unknown'; + return "Dotsave"; } function fetchPlayers() { diff --git a/UIMod/onboard_bundled/assets/js/sscm.js b/UIMod/onboard_bundled/assets/js/sscm.js index ce639c3c..724c5aee 100644 --- a/UIMod/onboard_bundled/assets/js/sscm.js +++ b/UIMod/onboard_bundled/assets/js/sscm.js @@ -127,15 +127,11 @@ function appendToConsole(message) { if (commandContainer) { consoleDiv.insertBefore(messageElement, commandContainer); // Insert before input + consoleDiv.scrollTop = consoleDiv.scrollHeight; } else { console.log("SSCM failed to insert command box"); return } - - // Auto-scroll only if at bottom - if (consoleDiv.scrollTop + consoleDiv.clientHeight >= consoleDiv.scrollHeight - 10) { - consoleDiv.scrollTop = consoleDiv.scrollHeight; - } } // Enhanced autocomplete functionality diff --git a/UIMod/onboard_bundled/assets/js/world-gen-config.js b/UIMod/onboard_bundled/assets/js/world-gen-config.js index 1210fb7d..24c1060f 100644 --- a/UIMod/onboard_bundled/assets/js/world-gen-config.js +++ b/UIMod/onboard_bundled/assets/js/world-gen-config.js @@ -1,32 +1,28 @@ // Validation configuration object const worldConfigs = { Lunar: { - conditions: ['DefaultStart', 'Brutal'], - locations: ['LunarSpawnCraterVesper', 'LunarSpawnMontesUmbrarum', 'LunarSpawnCraterNox', 'LunarSpawnMonsArcanus'] + conditions: ['DefaultStart', 'DefaultStartCommunity', 'Brutal', 'BrutalCommunity'], + locations: ['LunarSpawnRoundRobin', 'LunarSpawnCraterVesper', 'LunarSpawnMontesUmbrarum', 'LunarSpawnCraterNox', 'LunarSpawnMonsArcanus'] }, Mars2: { - conditions: ['DefaultStart', 'Brutal'], - locations: ['MarsSpawnCanyonOverlook', 'MarsSpawnButchersFlat', 'MarsSpawnFindersCanyon', 'MarsSpawnHellasCrags', 'MarsSpawnDonutFlats'] + conditions: ['DefaultStart', 'DefaultStartCommunity', 'Brutal', 'BrutalCommunity'], + locations: ['MarsSpawnRoundRobin', 'MarsSpawnCanyonOverlook', 'MarsSpawnButchersFlat', 'MarsSpawnFindersCanyon', 'MarsSpawnHellasCrags', 'MarsSpawnDonutFlats'] }, Europa3: { - conditions: ['EuropaDefault', 'EuropaBrutal'], - locations: ['EuropaSpawnIcyBasin', 'EuropaSpawnGlacialChannel', 'EuropaSpawnBalgatanPass', 'EuropaSpawnFrigidHighlands', 'EuropaSpawnTyreValley'] + conditions: ['EuropaDefault', 'EuropaDefaultCommunity', 'EuropaBrutal', 'EuropaBrutalCommunity'], + locations: ['EuropaSpawnRoundRobin','EuropaSpawnIcyBasin', 'EuropaSpawnGlacialChannel', 'EuropaSpawnBalgatanPass', 'EuropaSpawnFrigidHighlands', 'EuropaSpawnTyreValley'] }, MimasHerschel: { - conditions: ['MimasDefault', 'MimasBrutal'], - locations: ['MimasSpawnCentralMesa', 'MimasSpawnHarrietCrater', 'MimasSpawnCraterField', 'MimasSpawnDustBowl'] + conditions: ['MimasDefault', 'MimasDefaultCommunity', 'MimasBrutal', 'MimasBrutalCommunity'], + locations: ['MimasSpawnRoundRobin','MimasSpawnCentralMesa', 'MimasSpawnHarrietCrater', 'MimasSpawnCraterField', 'MimasSpawnDustBowl'] }, Vulcan2: { - conditions: ['VulcanDefault', 'VulcanBrutal'], - locations: ['VulcanSpawnVestaValley', 'VulcanSpawnEtnasFury', 'VulcanSpawnIxionsDemise', 'VulcanSpawnTitusReach'] - }, - Vulcan: { - conditions: ['VulcanDefault', 'VulcanBrutal'], - locations: ['VulcanSpawnVestaValley', 'VulcanSpawnEtnasFury', 'VulcanSpawnIxionsDemise', 'VulcanSpawnTitusReach'] + conditions: ['VulcanDefault', 'VulcanDefaultCommunity', 'VulcanDefaultCommunity', 'VulcanBrutal', 'VulcanBrutalCommunity'], + locations: ['VulcanSpawnRoundRobin', 'VulcanSpawnVestaValley', 'VulcanSpawnEtnasFury', 'VulcanSpawnIxionsDemise', 'VulcanSpawnTitusReach'] }, Venus: { - conditions: ['VenusDefault', 'VulcanBrutal (yes, VULCAN Brutal!)'], - locations: ['VenusSpawnGaiaValley', 'VenusSpawnDaisyValley', 'VenusSpawnFaithValley', 'VenusSpawnDuskValley'] + conditions: ['VenusDefault', 'VenusDefaultCommunity', 'VulcanBrutal', 'VulcanBrutalCommunity'], + locations: ['VenusSpawnRoundRobin', 'VenusSpawnGaiaValley', 'VenusSpawnDaisyValley', 'VenusSpawnFaithValley', 'VenusSpawnDuskValley'] } }; diff --git a/UIMod/onboard_bundled/assets/js/xmas.js b/UIMod/onboard_bundled/assets/js/xmas.js new file mode 100644 index 00000000..df9cbbef --- /dev/null +++ b/UIMod/onboard_bundled/assets/js/xmas.js @@ -0,0 +1,1082 @@ +document.addEventListener('DOMContentLoaded', function() { + + // Check if the date is between Dec 1 and Jan 10 (inclusive, across year boundary) + const now = new Date(); + const isXmas = (now.getMonth() === 11 && now.getDate() >= 1) || // Dec 1–31 + (now.getMonth() === 0 && now.getDate() <= 10); // Jan 1–10 + + // If Christmas period is over, do nothing + if (!isXmas) { + return; + } + + console.log('Christmas sleigh ready to fly'); + + // Inject the sleigh CSS + const sleighStyle = document.createElement('style'); + sleighStyle.textContent = ` + .sleigh-container { + position: fixed; + z-index: -1; + transition: transform 0.3s; + animation: flySleigh 30s linear infinite; + scale: 0.5; + } + + .sleigh-container:hover { + transform: scale(1.1);F + } + + @keyframes flySleigh { + 0% { + left: -400px; + top: 40%; + } + 50% { + top: 30%; + } + 100% { + left: calc(100% + 400px); + top: 20%; + } +} + + @keyframes bounce { + 0%, 100% { transform: translateX(-50%) translateY(0); } + 50% { transform: translateX(-50%) translateY(-8px); } + } + + /* Sleigh styles */ + .sleigh-santa { + position: relative; + width: 295px; + height: 155px; + transform: rotate(-1deg); + } + + .santa { + position: absolute; + bottom: 0; + left: 50%; + width: 125px; + height: 107px; + z-index: 10; + } + + .santa--sleigh { + bottom: 0; + left: 0; + transform: rotateY(180deg); + } + + .santa--sleigh:before, + .santa--sleigh:after { + content: ""; + position: absolute; + bottom: 0; + background-color: #8B0000; + } + + .santa--sleigh:before { + left: -10px; + width: 129px; + height: 30px; + border-radius: 5px 5% 10px 65%; + transform: rotate(0); + z-index: 10; + border-bottom: 2px solid #DAA520; + } + + .santa--sleigh:after { + border: 2px solid #DAA520; + left: 70px; + bottom: 0px; + width: 50px; + height: 57px; + border-radius: 50% 10px 16px 10px; + transform: rotate(1deg); + box-shadow: -98px -2px 0px -18px #8B0000; + } + + .santa__hat-part { + position: absolute; + top: 7px; + left: 31px; + width: 43px; + height: 58px; + border-radius: 50%; + transform: rotate(28deg); + background-color: #d63527; + } + + .santa__hat-part:before, + .santa__hat-part:after { + content: ""; + position: absolute; + } + + .santa__hat-part:nth-of-type(1):before { + top: 9px; + left: 45px; + width: 7px; + height: 7px; + border-radius: 50%; + background-color: #fff; + animation: santa-hat-bobble 1s linear alternate infinite; + } + + .santa__hat-part:nth-of-type(1):after { + top: 3px; + left: 19px; + width: 30px; + height: 7px; + border-radius: 50%; + transform: rotate(22deg); + background-color: #d63527; + animation: santa-hat-main 1s linear alternate infinite; + } + + .santa__hat-part:nth-of-type(2) { + position: absolute; + top: 18px; + left: 31px; + width: 44px; + height: 34px; + border-radius: 50%; + transform: rotate(12deg); + background-color: #fff; + } + + .santa__face { + position: absolute; + top: 25px; + left: 37px; + width: 31px; + height: 17px; + border-radius: 20px 20px 50% 50%; + transform: rotate(10deg); + background-color: #fde2b7; + z-index: 10; + } + + .santa__beard-part { + position: absolute; + top: 8px; + left: -14px; + width: 15px; + height: 17px; + border-radius: 50%; + background-color: #fff; + } + + .santa__beard-part:before, + .santa__beard-part:after { + content: ""; + position: absolute; + background-color: #fff; + } + + .santa__beard-part:before { + top: 12px; + left: 1px; + width: 15px; + height: 17px; + border-radius: 50%; + } + + .santa__beard-part:nth-of-type(2) { + top: 16px; + left: -8px; + width: 26px; + height: 30px; + } + + .santa__beard-part:nth-of-type(2):before { + top: 16px; + left: 13px; + width: 19px; + height: 17px; + } + + .santa__beard-part:nth-of-type(2):after { + top: 1px; + left: 13px; + width: 19px; + height: 17px; + } + + .santa__beard-part:nth-of-type(3) { + top: 16px; + left: 14px; + width: 27px; + height: 28px; + } + + .santa__beard-part:nth-of-type(3):before { + top: -4px; + left: 13px; + width: 17px; + height: 17px; + } + + .santa__eyebrows { + position: absolute; + top: 0; + left: 0; + width: 2px; + height: 7px; + border-radius: 50%; + background-color: #fff; + } + + .santa__eyebrows--left { + top: 1px; + left: 4px; + transform: rotate(65deg); + } + + .santa__eyebrows--right { + top: 2px; + left: 22px; + transform: rotate(-65deg); + } + + .santa__eye { + position: absolute; + width: 3px; + height: 4px; + border-radius: 50%; + background-color: #000; + } + + .santa__eye--left { + top: 8px; + left: 2px; + } + + .santa__eye--right { + top: 8px; + left: 20px; + } + + .santa__nose { + position: absolute; + top: 10px; + left: 6px; + width: 12px; + height: 9px; + border-radius: 50%; + z-index: 10; + background-color: #f7d194; + } + + .santa__cheek { + position: absolute; + width: 7px; + height: 7px; + border-radius: 50%; + z-index: 10; + background-color: #f4cfe3; + } + + .santa__cheek--left { + top: 12px; + left: -3px; + } + + .santa__cheek--right { + top: 13px; + left: 22px; + } + + .santa__body { + position: absolute; + top: 54px; + left: 16px; + width: 88px; + height: 53px; + } + + .santa__body:before { + content: ""; + position: absolute; + top: -23px; + right: -10px; + width: 53px; + height: 51px; + border-radius: 42% 50%; + background-color: #362312; + z-index: -1; + box-shadow: 10px -21px 0px -20px #e1b12c, 15px -30px 0px -18px #362312; + animation: santa-sac 0.6s linear alternate infinite; + } + + .santa__body-top { + top: -3px; + left: 10px; + position: absolute; + width: 45px; + height: 39px; + border-radius: 50% 50% 10% 10%; + background-color: #d63527; + z-index: 5; + } + + .santa__body-top:before { + content: ""; + top: 28px; + left: 0px; + position: absolute; + width: 45px; + height: 5px; + background-color: #000; + transform: rotate(1deg); + } + + .santa__body-top:after { + content: ""; + top: 27px; + left: 10px; + position: absolute; + width: 7px; + height: 5px; + background-color: #000; + border: 1px solid #fff; + border-radius: 3px; + transform: rotate(1deg); + } + + .santa__hand--left { + top: 5px; + left: 19px; + width: 33px; + height: 30px; + overflow: hidden; + position: absolute; + } + + .santa__hand-inner { + position: absolute; + top: 10px; + left: 8px; + width: 49px; + z-index: 100; + height: 7px; + border-radius: 10px; + transform: rotate(12deg); + background-color: #d63527; + animation: sleigh-santa-hand-left 1s linear alternate infinite; + } + + .santa__hand-inner:before { + content: ""; + position: absolute; + width: 8px; + height: 7px; + top: -2px; + left: -6px; + background-color: #000; + border-radius: 50%; + transform: rotate(25deg); + } + + .santa__hand--right { + position: absolute; + top: 4px; + left: 3px; + width: 11px; + height: 8px; + transform: rotate(25deg); + border-radius: 10px; + height: 7px; + background-color: #d63527; + animation: sleigh-santa-hand-right 1s linear alternate infinite; + } + + .santa__hand--right:before { + content: ""; + position: absolute; + width: 8px; + height: 7px; + top: -2px; + left: -6px; + background-color: #000; + border-radius: 50%; + transform: rotate(10deg); + } + + .sleigh-feet { + position: absolute; + bottom: -10px; + left: 0px; + width: 145px; + height: 11px; + transform: rotate(-5deg); + border-bottom: 5px solid #996515; + border-right: 5px solid #996515; + border-radius: 10px; + z-index: 2; + } + + .sleigh-feet:before, + .sleigh-feet:after { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 5px; + height: 5px; + background-color: #996515; + } + + .sleigh-feet:before { + top: 2px; + left: 34px; + height: 9px; + } + + .sleigh-feet:after { + top: 3px; + left: 108px; + width: 5px; + height: 8px; + } + + .lead { + position: absolute; + top: 92px; + left: 84px; + width: 182px; + height: 33px; + overflow: hidden; + z-index: 10; + transform: rotate(0deg); + animation: sleigh-santa-lead-right 1s linear alternate infinite; + } + + .lead--back { + top: 85px; + left: 105px; + width: 149px; + transform: rotate(4deg); + z-index: 0; + animation: sleigh-santa-lead-left 1s linear alternate infinite; + } + + .lead-inner { + position: absolute; + bottom: 0; + left: -12px; + width: 100%; + height: 48px; + border-bottom: 1px solid #fff; + border-radius: 50%; + } + + .reindeer { + position: absolute; + width: 115px; + height: 155px; + right: 5px; + top: 17px; + transform: rotate(25deg); + z-index: 0; + } + + .reindeer:before { + content: ""; + position: absolute; + top: 65px; + left: 76px; + width: 8px; + height: 31px; + background-color: #8B0000; + z-index: 10; + transform: rotate(-55deg); + } + + .reindeer:after { + content: ""; + position: absolute; + height: 5px; + width: 5px; + border-radius: 50%; + background-color: #DAA520; + z-index: 11; + left: 64px; + top: 68px; + box-shadow: 8px 6px 0 0 #DAA520, 18px 13px 0 0 #DAA520, 26px 18px 0 0 #DAA520; + } + + .reindeer__face { + position: absolute; + width: 30px; + height: 22px; + top: 44px; + left: 72px; + border-radius: 10px 10px 50% 50%; + transform: rotate(-3deg); + background-color: #654321; + animation: reindeer-face 1.6s linear alternate infinite; + } + + .reindeer__face:before { + content: ""; + position: absolute; + background-color: #654321; + width: 29px; + height: 16px; + border-radius: 50%; + top: 0px; + left: 11px; + transform: rotate(-49deg); + } + + .reindeer__face:after { + content: ""; + position: absolute; + background-color: #8B0000; + width: 8px; + height: 8px; + border-radius: 50%; + top: -8px; + left: 31px; + } + + .reindeer__horn { + position: absolute; + width: 29px; + height: 4px; + border-radius: 2px; + background-color: #DEB887; + } + + .reindeer__horn:before, + .reindeer__horn:after { + content: ""; + position: absolute; + background-color: #DEB887; + border-radius: 2px; + } + + .reindeer__horn--left { + top: -7px; + left: -21px; + transform: rotate(38deg); + } + + .reindeer__horn--left:before { + top: -4px; + left: 6px; + width: 14px; + height: 4px; + transform: rotate(43deg); + } + + .reindeer__horn--left:after { + top: -4px; + left: 13px; + width: 14px; + height: 4px; + transform: rotate(53deg); + } + + .reindeer__horn--right { + top: -12px; + left: -6px; + width: 24px; + transform: rotate(62deg); + } + + .reindeer__horn--right:before { + top: -3px; + left: 5px; + width: 10px; + height: 4px; + transform: rotate(43deg); + } + + .reindeer__horn--right:after { + top: -3px; + left: 11px; + width: 10px; + height: 4px; + transform: rotate(53deg); + } + + .reindeer__ear { + position: absolute; + width: 21px; + height: 11px; + top: 4px; + left: -18px; + border-radius: 4px 0 50% 50%; + transform: rotate(4deg); + background-color: #654321; + } + + .reindeer__ear:before { + content: ""; + position: absolute; + top: -2px; + left: 34px; + width: 4px; + height: 5px; + border-radius: 50%; + transform: rotate(-35deg); + background-color: #000; + } + + .reindeer__body { + position: absolute; + width: 58px; + height: 31px; + top: 84px; + left: 28px; + border-radius: 50% 0; + transform: rotate(-3deg); + background-color: #654321; + } + + .reindeer__body:before { + content: ""; + position: absolute; + width: 46px; + height: 26px; + top: -15px; + left: 32px; + border-radius: 0 0 50% 50%; + transform: rotate(-55deg); + background-color: #654321; + } + + .reindeer__body:after { + content: ""; + position: absolute; + width: 43px; + height: 26px; + top: -11px; + left: 29px; + border-radius: 0 0 50% 50%; + transform: rotate(-30deg); + background-color: #654321; + } + + .reindeer__foot--inside { + z-index: 2; + transform: rotate(-12deg) translate(3px, 0px); + } + + .reindeer__foot-inner { + position: absolute; + } + + .reindeer__foot-inner:before, + .reindeer__foot-inner:after { + content: ""; + position: absolute; + } + + .reindeer__foot--front .reindeer__foot-inner { + width: 40px; + height: 8px; + top: 13px; + left: 35px; + border-radius: 0 50%; + transform: rotate(-17deg); + transform-origin: center; + background-color: #654321; + animation: reindeer-front 1.6s linear alternate infinite; + } + + .reindeer__foot--front .reindeer__foot-inner:before { + width: 28px; + height: 8px; + top: 0px; + left: 37px; + border-radius: 2px 50%; + transform: rotate(131deg); + background-color: #654321; + animation: reindeer-front-ext 1.7s linear alternate infinite; + } + + .reindeer__foot--front .reindeer__foot-inner:after { + width: 8px; + height: 9px; + top: 27px; + left: 32px; + border-radius: 2px; + transform: rotate(131deg); + background-color: #362514; + animation: reindeer-front-ext-hoof 1.7s linear alternate infinite; + } + + .reindeer__foot--back .reindeer__foot-inner { + width: 56px; + height: 9px; + top: 35px; + left: -29px; + border-radius: 0 50%; + transform: rotate(-73deg); + background-color: #654321; + animation: reindeer-back 1.7s linear alternate infinite; + } + + .reindeer__foot--back .reindeer__foot-inner:before { + width: 25px; + height: 16px; + top: 4px; + left: 25px; + border-radius: 0 50%; + transform: rotate(15deg); + background-color: #654321; + } + + .reindeer__foot--back .reindeer__foot-inner:after { + width: 8px; + height: 9px; + top: -2px; + left: -2px; + border-radius: 2px 0 2px 2px; + transform: rotate(14deg); + background-color: #362514; + } + + .reindeer__tail { + position: absolute; + width: 27px; + height: 26px; + top: 6px; + left: -8px; + border-radius: 50% 2px; + transform: rotate(-17deg); + background-color: #654321; + } + + .reindeer__tail:before { + content: ""; + position: absolute; + background-color: #654321; + border-radius: 50%; + top: -2px; + left: -3px; + width: 15px; + height: 5px; + transform: rotate(25deg); + } + + .reindeer__spots { + position: absolute; + width: 4px; + height: 4px; + top: 6px; + left: 8px; + border-radius: 50% 2px; + background-color: #DEB887; + box-shadow: 5px 5px 0 0 #DEB887, -5px 5px 0 0 #DEB887; + } + + .particles { + position: absolute; + bottom: -30px; + left: 0; + width: 7px; + height: 7px; + background-color: transparent; + transform: rotate(45deg); + z-index: -10; + } + + .particles:before, + .particles:after { + position: absolute; + content: ""; + background-color: #FFF; + } + + .particles:after { + left: 0px; + top: 0px; + width: 4px; + height: 4px; + transform: rotate(-5deg); + animation: particles 4s linear infinite; + box-shadow: -20px 15px 0px 0px #FFF, -40px -5px 0px 0px #FFF, -20px 45px 0px 0px #FFF, -50px 30px 0px 0px #FFF, 30px -20px 0px 0px #FFF, 50px -60px 0px 0px #FFF, 100px -110px 0px 0px #FFF, 140px -160px 0px 0px #FFF, 50px -90px 0px 0px #FFF, 100px -140px 0px 0px #FFF, 140px -190px 0px 0px #FFF; + } + + .particles:before { + left: 10px; + top: 0px; + width: 2px; + height: 2px; + transform: rotate(-10deg); + animation: particles 5s linear infinite; + box-shadow: -20px 15px 0px 0px #FFF, -40px -5px 0px 0px #FFF, -20px 45px 0px 0px #FFF, -50px 30px 0px 0px #FFF, 30px -20px 0px 0px #FFF, 50px -60px 0px 0px #FFF, 100px -110px 0px 0px #FFF, 140px -160px 0px 0px #FFF, 50px -90px 0px 0px #FFF, 100px -140px 0px 0px #FFF, 140px -190px 0px 0px #FFF; + } + + @keyframes reindeer-face { + 0% { transform: rotate(-8deg); } + 100% { transform: rotate(2deg); } + } + + @keyframes reindeer-back { + 0% { transform: rotate(-81deg) translate(-6px, 0px); } + 100% { transform: rotate(-60deg) translate(0px, 0px); } + } + + @keyframes reindeer-front { + 0% { transform: rotate(-24deg); } + 100% { transform: rotate(-13deg); } + } + + @keyframes reindeer-front-ext { + 0% { + transform-origin: left; + transform: rotate(55deg); + } + 100% { + transform-origin: left; + transform: rotate(145deg); + } + } + + @keyframes reindeer-front-ext-hoof { + 0% { + transform-origin: left top; + transform: rotate(-32deg) translate(14px, 1px); + } + 100% { + transform-origin: left top; + transform: rotate(52deg) translate(-21px, 0px); + } + } + + @keyframes sleigh-santa-lead-left { + 0% { transform: rotate(1deg); } + 100% { transform: rotate(-2deg); } + } + + @keyframes sleigh-santa-hand-left { + 0% { transform: rotate(15deg); } + 100% { transform: rotate(-2deg); } + } + + @keyframes sleigh-santa-lead-right { + 0% { transform: rotate(2deg); } + 100% { transform: rotate(-4deg); } + } + + @keyframes sleigh-santa-hand-right { + 0% { transform: rotate(15deg); } + 100% { transform: rotate(-30deg); } + } + + @keyframes santa-hat-main { + 0% { + transform-origin: left; + transform: rotate(-15deg); + } + 100% { + transform-origin: left; + transform: rotate(15deg); + } + } + + @keyframes santa-hat-bobble { + 0% { transform: translate(0px, -15px); } + 100% { transform: translate(0px, 5px); } + } + + @keyframes santa-sac { + 0% { transform: rotate(5deg); } + 100% { transform: rotate(0deg); } + } + + @keyframes particles { + 0% { + transform: translate(20px, -20px); + opacity: 1; + } + 100% { + transform: translate(-80px, 80px); + opacity: 0; + } + } + `; + document.head.appendChild(sleighStyle); + + // Create the sleigh container + const sleighContainer = document.createElement('div'); + sleighContainer.className = 'sleigh-container'; + sleighContainer.innerHTML = ` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`; +document.body.appendChild(sleighContainer); +// make the stars snowflakes moving downwards + +const style = document.createElement('style'); + style.textContent = ` + @keyframes stars { + 0% { transform: translateY(0px); } + 100% { transform: translateY(+2000px); } + } + @keyframes stars { + 0% { transform: translateY(0); } + 100% { transform: translateY(3000px); } + } + + #space-background::before { + background-image: + radial-gradient(2px 2px at 17px 43px, #fff, transparent), + radial-gradient(2px 2px at 39px 157px, #fff, transparent), + radial-gradient(2px 2px at 73px 91px, #fff, transparent), + radial-gradient(2px 2px at 109px 134px, #fff, transparent), + radial-gradient(2px 2px at 143px 27px, #fff, transparent), + radial-gradient(2px 2px at 53px 79px, #fff, transparent), + radial-gradient(2px 2px at 85px 123px, #fff, transparent), + radial-gradient(2px 2px at 174px 36px, #fff, transparent), + radial-gradient(2px 2px at 102px 64px, #fff, transparent), + radial-gradient(2px 2px at 127px 187px, #fff, transparent); + background-size: 250px 250px; + opacity: 0.6; + animation: none !important; /* Static layer - no movement */ + } + + /* Moving larger/closer snowflakes layer (replaces Layer 2 stars) */ + #space-background::after { + background-image: + radial-gradient(4px 4px at 43px 267px, #fff, transparent), + radial-gradient(4px 4px at 167px 312px, #fff, transparent), + radial-gradient(4px 4px at 213px 117px, #fff, transparent), + radial-gradient(4px 4px at 81px 209px, #fff, transparent), + radial-gradient(4px 4px at 239px 349px, #fff, transparent), + radial-gradient(4px 4px at 124px 281px, #fff, transparent), + radial-gradient(4px 4px at 198px 153px, #fff, transparent), + radial-gradient(4px 4px at 56px 379px, #fff, transparent), + radial-gradient(3px 3px at 297px 246px, #fff, transparent), + radial-gradient(3px 3px at 147px 133px, #fff, transparent); + background-size: 400px 400px; + opacity: 0.8; + animation: stars 180s linear infinite !important; /* Slower for gentle snow fall */ + } + + `; + document.head.appendChild(style); + + +function addChristmasOrbitingTreats() { + // Hide original orbits + document.querySelectorAll('.orbit').forEach(orbit => { + orbit.style.display = 'none'; + }); + + const container = document.getElementById('planet-container'); + if (!container) return; + + // Helper to create a properly positioned orbiting image + function createOrbitingImage(imgUrl, size, orbitRadius, speed, delay = 0) { + const orbit = document.createElement('div'); + orbit.classList.add('orbit'); + orbit.style.width = `${orbitRadius * 2}px`; + orbit.style.height = `${orbitRadius * 2}px`; + orbit.style.position = 'absolute'; + orbit.style.left = '50%'; + orbit.style.top = '50%'; + orbit.style.transform = 'translate(-50%, -50%)'; + orbit.style.animation = `orbit ${speed}s linear infinite ${delay}s`; + + const img = document.createElement('img'); + img.src = imgUrl; + img.style.width = `${size}px`; + img.style.height = `${size}px`; + img.style.objectFit = 'contain'; + img.style.position = 'absolute'; + img.style.left = '0'; + img.style.top = '50%'; + img.style.transform = 'translateY(-50%)'; + img.style.pointerEvents = 'none'; + img.style.filter = 'drop-shadow(0 0 20px rgba(255,255,255,0.7))'; + + orbit.appendChild(img); + container.appendChild(orbit); + } + + // Better transparent PNGs for cleaner look + createOrbitingImage('/static/xmas/c4.webp', 130, 1100, 40, -5); + + createOrbitingImage('/static/xmas/c3.webp', 100, 850, 55, -12); + + createOrbitingImage('/static/xmas/c2.webp', 120, 600, 65, -20); + + createOrbitingImage('/static/xmas/c1.webp', 110, 400, 32, -8); +} + +function replaceBanner() { + const banner = document.getElementById('banner'); + banner.src = '/static/xmas/stationeers-winter.webp'; +} + +addChristmasOrbitingTreats(); +replaceBanner(); + +}); \ No newline at end of file diff --git a/UIMod/onboard_bundled/assets/xmas/c1.webp b/UIMod/onboard_bundled/assets/xmas/c1.webp new file mode 100644 index 00000000..e8df7026 Binary files /dev/null and b/UIMod/onboard_bundled/assets/xmas/c1.webp differ diff --git a/UIMod/onboard_bundled/assets/xmas/c2.webp b/UIMod/onboard_bundled/assets/xmas/c2.webp new file mode 100644 index 00000000..70876ecb Binary files /dev/null and b/UIMod/onboard_bundled/assets/xmas/c2.webp differ diff --git a/UIMod/onboard_bundled/assets/xmas/c3.webp b/UIMod/onboard_bundled/assets/xmas/c3.webp new file mode 100644 index 00000000..9023426d Binary files /dev/null and b/UIMod/onboard_bundled/assets/xmas/c3.webp differ diff --git a/UIMod/onboard_bundled/assets/xmas/c4.webp b/UIMod/onboard_bundled/assets/xmas/c4.webp new file mode 100644 index 00000000..2e3f7697 Binary files /dev/null and b/UIMod/onboard_bundled/assets/xmas/c4.webp differ diff --git a/UIMod/onboard_bundled/assets/xmas/stationeers-winter.webp b/UIMod/onboard_bundled/assets/xmas/stationeers-winter.webp new file mode 100644 index 00000000..4043b98e Binary files /dev/null and b/UIMod/onboard_bundled/assets/xmas/stationeers-winter.webp differ diff --git a/UIMod/onboard_bundled/localization/en-US.json b/UIMod/onboard_bundled/localization/en-US.json index bda9e741..adbbd138 100644 --- a/UIMod/onboard_bundled/localization/en-US.json +++ b/UIMod/onboard_bundled/localization/en-US.json @@ -49,7 +49,7 @@ "UIText_SaveName": "Save Name", "UIText_SaveNameInfo": "Name of the save folder, like 'MySave' or 'Europa Brutal'", "UIText_WorldID": "World ID", - "UIText_WorldIDInfo": "World ID used when creating a new world. For a list of world IDs, see the Dedicated Server Wiki or configure it easily from the setup wizard." + "UIText_WorldIDInfo": "World ID used when creating a new world. For a list of world IDs, see the Dedicated Server Wiki or configure them easily from the setup wizard. For more options, see the World generation tab." }, "network": { "UIText_NetworkConfiguration": "Network Configuration", @@ -60,7 +60,7 @@ "UIText_UPNPEnabled": "UPNP Enabled", "UIText_UPNPEnabledInfo": "Enable automatic UPNP port forwarding", "UIText_LocalIpAddress": "Local IP Address", - "UIText_LocalIpAddressInfo": "IP address to bind to", + "UIText_LocalIpAddressInfo": "IP address to bind to. Recommended to leave at 0.0.0.0 unless you really know what you're doing.", "UIText_StartLocalHost": "Start Local Host", "UIText_StartLocalHostInfo": "Keep this true. This is required for the server to work.", "UIText_ServerVisible": "Server Visible", @@ -84,7 +84,12 @@ "UIText_AllowAutoGameServerUpdates": "Enable Auto Game Server Updates", "UIText_AllowAutoGameServerUpdatesInfo": "Allow the gameserver to automatically query for and update to the latest version. Attention: Restarts the server when a new version was found and installed. Will send multiple warning messages to the sever with SAY commands 60-10 seconds before the restart.", "UIText_AutoStartServerOnStartup": "Auto Start Server on Startup", - "UIText_AutoStartServerOnStartupInfo": "Automatically start the gameserver when the SSUI is started. Defaults to false." + "UIText_AutoStartServerOnStartupInfo": "Automatically start the gameserver when the SSUI is started. Defaults to false.", + "UIText_CreateSSUILogFile": "Create SSUI Log Files", + "UIText_CreateSSUILogFileInfo": "Create log files for the SSUI log in UIMod/logs. Defaults to false.", + "UIText_CreateGameServerLogFile": "Create Game Server Log File", + "UIText_CreateGameServerLogFileInfo": "Create a unique log file per server start for the gameserver in UIMod/logs. Defaults to false." + }, "terrain": { "UIText_TerrainSettingsHeader": "Optional world generation settings", diff --git a/UIMod/onboard_bundled/ui/config.html b/UIMod/onboard_bundled/ui/config.html index b080d61c..5672510b 100644 --- a/UIMod/onboard_bundled/ui/config.html +++ b/UIMod/onboard_bundled/ui/config.html @@ -256,6 +256,24 @@

{{.UIText_AdvancedConfiguration}}

{{.UIText_AllowAutoGameServerUpdatesInfo}}
+ +
+ + +
{{.UIText_CreateSSUILogFileInfo}}
+
+ +
+ + +
{{.UIText_CreateGameServerLogFileInfo}}
+
@@ -266,6 +284,12 @@

{{.UIText_TerrainSettingsHeader}}


+
+ + +
{{.UIText_WorldIDInfo}}
+
+
{{.UIText_DiscordIntegrationBenefits}} + \ No newline at end of file diff --git a/UIMod/onboard_bundled/ui/index.html b/UIMod/onboard_bundled/ui/index.html index 4e70928e..71339142 100644 --- a/UIMod/onboard_bundled/ui/index.html +++ b/UIMod/onboard_bundled/ui/index.html @@ -63,6 +63,24 @@

Stationeers Server UI v{{.Version}}{{.SSUIIdentifier}}

+ +

{{.UIText_Connected_PlayersHeader}}

@@ -70,42 +88,24 @@

{{.UIText_Connected_PlayersHeader}}

-

{{.UIText_Backup_Manager}}

-
- - -
- -
- -