diff --git a/UIMod/onboard_bundled/assets/css/apiinfo.css b/UIMod/onboard_bundled/assets/css/apiinfo.css index 8d160e4f..73c59b55 100644 --- a/UIMod/onboard_bundled/assets/css/apiinfo.css +++ b/UIMod/onboard_bundled/assets/css/apiinfo.css @@ -16,17 +16,17 @@ .version-tag { background-color: var(--accent); - color: white; + color: var(--text-header); } .status-tag { background-color: var(--success); - color: white; + color: var(--text-header); } .api-overview { margin-bottom: 30px; - background-color: rgba(0, 0, 0, 0.2); + background-color: var(--form-bg); padding: 20px; border-radius: 8px; border-left: 4px solid var(--accent); @@ -46,16 +46,16 @@ } .endpoint { - background-color: rgba(0, 0, 0, 0.2); + background-color: var(--form-bg); padding: 15px; border-radius: 8px; - border: 1px solid rgba(0, 255, 171, 0.3); + border: 1px solid var(--primary-glow); transition: transform var(--transition-normal), box-shadow var(--transition-normal); } .endpoint:hover { transform: translateY(-3px); - box-shadow: 0 5px 15px rgba(0, 255, 171, 0.2); + box-shadow: 0 5px 15px var(--primary-bg-medium); } .api-list { @@ -66,7 +66,7 @@ .api-list li { margin-bottom: 15px; padding: 10px; - background-color: rgba(0, 0, 0, 0.4); + background-color: var(--nav-bg); border-radius: 4px; display: flex; flex-wrap: wrap; @@ -76,7 +76,7 @@ } .api-list li:hover { - background-color: rgba(0, 0, 0, 0.6); + background-color: var(--nav-bg-hover); } .method { @@ -84,15 +84,15 @@ border-radius: 4px; font-size: 0.7rem; font-weight: bold; - color: white; + color: var(--text-header); } .method.get { - background-color: #61affe; + background-color: var(--accent); } .method.post { - background-color: #49cc90; + background-color: var(--success); } .endpoint-link { @@ -107,7 +107,7 @@ a.endpoint-link:hover { .endpoint-desc { font-size: 0.85rem; - color: #aaa; + color: var(--text-dim); width: 100%; margin-top: 5px; } @@ -117,7 +117,7 @@ a.endpoint-link:hover { } .code-block { - background-color: rgba(0, 0, 0, 0.4); + background-color: var(--nav-bg); padding: 20px; border-radius: 8px; border-left: 4px solid var(--accent); @@ -125,6 +125,6 @@ a.endpoint-link:hover { } .hint { - color: #aaa; + color: var(--text-dim); font-style: italic; } \ 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 10282311..bc4ac966 100644 --- a/UIMod/onboard_bundled/assets/css/background.css +++ b/UIMod/onboard_bundled/assets/css/background.css @@ -16,8 +16,8 @@ header { position: absolute; inset: 0; background: - linear-gradient(rgba(0, 255, 171, 0.05) 1px, transparent 1px), - linear-gradient(90deg, rgba(0, 255, 171, 0.05) 1px, transparent 1px); + linear-gradient(color-mix(in srgb, var(--primary) 5%, transparent) 1px, transparent 1px), + linear-gradient(90deg, color-mix(in srgb, var(--primary) 5%, transparent) 1px, transparent 1px); background-size: 20px 20px; background-position: center center; z-index: 0; @@ -29,7 +29,7 @@ header { left: 0; width: 100%; height: 100%; - background: radial-gradient(ellipse at bottom, #1b2735 0%, var(--bg-dark) 100%); + background: radial-gradient(ellipse at bottom, color-mix(in srgb, var(--bg-dark) 70%, var(--bg-panel)) 0%, var(--bg-dark) 100%); z-index: -2; will-change: transform; overflow: hidden; @@ -106,7 +106,7 @@ header { radial-gradient(1px 1px at 102px 64px, var(--text-bright), transparent), radial-gradient(1px 1px at 127px 187px, var(--text-header), transparent), radial-gradient(700px 500px at 65% 75%, var(--primary-glow), transparent), - radial-gradient(500px 400px at 20% 25%, rgba(0, 132, 255, 0.15), transparent); + radial-gradient(500px 400px at 20% 25%, color-mix(in srgb, var(--accent) 15%, transparent), transparent); background-size: 250px 250px, 250px 250px, 250px 250px, 250px 250px, 250px 250px, 250px 250px, 250px 250px, 250px 250px, 250px 250px, 250px 250px, 100% 100%, 100% 100%; diff --git a/UIMod/onboard_bundled/assets/css/config.css b/UIMod/onboard_bundled/assets/css/config.css index f4dea0d1..ff3d3d2e 100644 --- a/UIMod/onboard_bundled/assets/css/config.css +++ b/UIMod/onboard_bundled/assets/css/config.css @@ -256,7 +256,7 @@ .fill-hint { font-size: 1rem; - color: #ffffff; + color: var(--text-header); padding: 2%; font-style: italic; text-align: center; @@ -312,7 +312,7 @@ select option { .input-info { font-size: 0.85rem; - color: #aaa; + color: var(--text-dim); margin-top: 5px; font-style: italic; } @@ -331,7 +331,7 @@ select option { gap: 15px; margin-bottom: 30px; padding: 15px; - background-color: rgba(0, 0, 0, 0.3); + background-color: var(--overlay-bg); border-radius: 8px; transition: transform var(--transition-normal), box-shadow var(--transition-normal); } @@ -349,7 +349,7 @@ select option { .feature-badge { background-color: var(--primary); - color: black; + color: var(--bg-dark); padding: 5px 10px; border-radius: 20px; font-size: 0.7rem; @@ -402,7 +402,7 @@ select option { .feature-list li { padding: 8px; margin-bottom: 10px; - background-color: rgba(0, 0, 0, 0.3); + background-color: var(--overlay-bg); border-radius: 4px; border-left: 3px solid var(--accent); transition: transform var(--transition-fast), background-color var(--transition-fast); @@ -410,7 +410,7 @@ select option { .feature-list li:hover { transform: translateX(3px); - background-color: rgba(0, 0, 0, 0.4); + background-color: var(--nav-bg); } @media (max-width: 768px) { @@ -455,11 +455,11 @@ select option { .slp-section:hover { border-color: var(--primary); - box-shadow: 0 0 15px rgba(0, 255, 150, 0.1); + box-shadow: 0 0 15px var(--primary-glow-soft); } .slp-section p { - color: var(--text-normal, #aaa); + color: var(--text-dim); font-family: 'Share Tech Mono', monospace; font-size: 0.9rem; line-height: 1.6; @@ -477,15 +477,15 @@ select option { } .slp-install-section { - background: linear-gradient(135deg, rgba(0, 255, 150, 0.08), rgba(0, 150, 255, 0.08)); + background: linear-gradient(135deg, var(--primary-glow-soft), color-mix(in srgb, var(--accent) 8%, transparent)); border: 2px solid var(--primary); - box-shadow: 0 0 25px rgba(0, 255, 150, 0.15); + box-shadow: 0 0 25px var(--primary-bg-light); text-align: center; padding: 40px; } .slp-install-section:hover { - box-shadow: 0 0 35px rgba(0, 255, 150, 0.25); + box-shadow: 0 0 35px var(--primary-bg-medium); } .slp-install-header { @@ -498,7 +498,7 @@ select option { .slp-install-icon { font-size: 52px; - filter: drop-shadow(0 0 10px rgba(0, 255, 150, 0.5)); + filter: drop-shadow(0 0 10px var(--primary-glow-strong)); } .slp-install-header h3 { @@ -508,7 +508,7 @@ select option { margin: 0; padding: 0; border: none; - text-shadow: 0 0 10px rgba(0, 255, 150, 0.3); + text-shadow: 0 0 10px var(--primary-glow); } .slp-button { @@ -526,7 +526,7 @@ select option { transition: all 0.2s ease; font-family: 'Share Tech Mono', monospace; font-size: 0.85rem; - box-shadow: 0 4px 15px rgba(0, 255, 150, 0.25); + box-shadow: 0 4px 15px var(--primary-bg-medium); margin: 8px 0; text-transform: uppercase; letter-spacing: 0.5px; @@ -534,12 +534,12 @@ select option { .slp-button:hover:not(:disabled) { transform: translateY(-3px); - box-shadow: 0 6px 25px rgba(0, 255, 150, 0.4); + box-shadow: 0 6px 25px var(--primary-glow-medium); } .slp-button:active:not(:disabled) { transform: translateY(-1px); - box-shadow: 0 3px 15px rgba(0, 255, 150, 0.3); + box-shadow: 0 3px 15px var(--primary-glow); } .slp-button:disabled { @@ -563,11 +563,11 @@ select option { min-width: 320px; padding: 18px 36px; font-size: 0.9rem; - box-shadow: 0 4px 20px rgba(0, 255, 150, 0.35); + box-shadow: 0 4px 20px var(--primary-glow); } .slp-button-large:hover:not(:disabled) { - box-shadow: 0 8px 35px rgba(0, 255, 150, 0.5); + box-shadow: 0 8px 35px var(--primary-glow-strong); } .slp-button-small { @@ -577,19 +577,19 @@ select option { } .slp-button.danger { - background-color: #e53935; - border-color: #e53935; - box-shadow: 0 4px 15px rgba(229, 57, 53, 0.25); + background-color: var(--danger); + border-color: var(--danger); + box-shadow: 0 4px 15px color-mix(in srgb, var(--danger) 25%, transparent); } .slp-button.danger:hover:not(:disabled) { - background-color: #ff5252; - border-color: #ff5252; - box-shadow: 0 6px 25px rgba(255, 82, 82, 0.4); + background-color: color-mix(in srgb, var(--danger) 80%, white); + border-color: color-mix(in srgb, var(--danger) 80%, white); + box-shadow: 0 6px 25px color-mix(in srgb, var(--danger) 40%, transparent); } .slp-manage-section { - border: 1px solid rgba(0, 255, 150, 0.2); + border: 1px solid var(--primary-bg-medium); } .manage-buttons { @@ -604,7 +604,7 @@ select option { display: flex; flex-direction: column; padding: 15px; - background: rgba(0, 0, 0, 0.2); + background: var(--form-bg); border-radius: 8px; border: 1px solid rgba(255, 255, 255, 0.05); } @@ -635,23 +635,23 @@ select option { text-align: center; cursor: pointer; transition: all 0.25s ease; - background: linear-gradient(145deg, rgba(0, 255, 150, 0.03), rgba(0, 150, 255, 0.03)); + background: linear-gradient(145deg, var(--primary-bg-subtle), color-mix(in srgb, var(--accent) 3%, transparent)); position: relative; margin: 20px 0; } #modPackageUploadZone:hover:not(.upload-zone-disabled) { border-color: var(--primary); - background: linear-gradient(145deg, rgba(0, 255, 150, 0.08), rgba(0, 150, 255, 0.08)); - box-shadow: 0 0 25px rgba(0, 255, 150, 0.15); + background: linear-gradient(145deg, var(--primary-glow-soft), color-mix(in srgb, var(--accent) 8%, transparent)); + box-shadow: 0 0 25px var(--primary-bg-light); transform: translateY(-2px); } #modPackageUploadZone.highlight { border-color: var(--primary); border-style: solid; - background: linear-gradient(145deg, rgba(0, 255, 150, 0.12), rgba(0, 150, 255, 0.12)); - box-shadow: 0 0 30px rgba(0, 255, 150, 0.25); + background: linear-gradient(145deg, var(--primary-bg-light), color-mix(in srgb, var(--accent) 12%, transparent)); + box-shadow: 0 0 30px var(--primary-bg-medium); } .upload-zone-disabled { @@ -670,7 +670,7 @@ select option { font-size: 56px; margin-bottom: 18px; display: block; - filter: drop-shadow(0 0 8px rgba(0, 255, 150, 0.3)); + filter: drop-shadow(0 0 8px var(--primary-glow)); } .upload-text { @@ -722,29 +722,29 @@ select option { text-align: center; max-width: 500px; padding: 50px; - background: linear-gradient(135deg, rgba(255, 170, 0, 0.08), rgba(255, 100, 0, 0.08)); - border: 2px solid rgba(255, 170, 0, 0.5); + background: linear-gradient(135deg, color-mix(in srgb, var(--warning) 8%, transparent), color-mix(in srgb, var(--warning) 5%, transparent)); + border: 2px solid color-mix(in srgb, var(--warning) 50%, transparent); border-radius: 16px; - box-shadow: 0 0 30px rgba(255, 170, 0, 0.15); + box-shadow: 0 0 30px color-mix(in srgb, var(--warning) 15%, transparent); } .slp-disclaimer-icon { font-size: 64px; display: block; margin-bottom: 20px; - filter: drop-shadow(0 0 15px rgba(255, 170, 0, 0.5)); + filter: drop-shadow(0 0 15px color-mix(in srgb, var(--warning) 50%, transparent)); } .slp-disclaimer-content h2 { - color: #ffaa00; + color: var(--warning); font-family: 'Press Start 2P', cursive; font-size: 1.2rem; margin: 0 0 25px 0; - text-shadow: 0 0 15px rgba(255, 170, 0, 0.4); + text-shadow: 0 0 15px color-mix(in srgb, var(--warning) 40%, transparent); } .slp-disclaimer-content p { - color: var(--text-normal, #ccc); + color: var(--text-dim); font-family: 'Share Tech Mono', monospace; font-size: 1rem; line-height: 1.8; @@ -776,27 +776,27 @@ select option { } .notification.success { - background-color: rgba(0, 255, 150, 0.1); - border-color: #00ff96; - color: #00ff96; + background-color: color-mix(in srgb, var(--success) 10%, transparent); + border-color: var(--success); + color: var(--success); } .notification.error { - background-color: rgba(255, 68, 68, 0.1); - border-color: #ff4444; - color: #ff6666; + background-color: color-mix(in srgb, var(--danger) 10%, transparent); + border-color: var(--danger); + color: var(--danger); } .notification.info { - background-color: rgba(0, 200, 255, 0.1); - border-color: #00c8ff; - color: #00d4ff; + background-color: color-mix(in srgb, var(--accent) 10%, transparent); + border-color: var(--accent); + color: var(--accent); } .notification.warning { - background-color: rgba(255, 200, 0, 0.1); - border-color: #ffc800; - color: #ffd700; + background-color: color-mix(in srgb, var(--warning) 10%, transparent); + border-color: var(--warning); + color: var(--warning); } @keyframes slideIn { @@ -818,7 +818,7 @@ select option { } .mod-card { - background: #11111142; + background: color-mix(in srgb, var(--bg-dark) 80%, transparent); border: 2px solid var(--primary-dim); border-radius: 12px; padding: 20px; @@ -835,7 +835,7 @@ select option { .mod-image-container { width: 100%; height: 250px; - background: var(--input-bg, #0f0f1e); + background: var(--input-bg); border: 2px solid var(--primary-dim); border-radius: 8px; overflow: hidden; @@ -857,7 +857,7 @@ select option { display: flex; align-items: center; justify-content: center; - color: var(--text-dim, #888); + color: var(--text-dim); font-size: 3rem; } @@ -879,14 +879,14 @@ select option { } .mod-version { - color: var(--text-dim, #888); + color: var(--text-dim); font-size: 0.8rem; margin-bottom: 10px; font-family: 'Share Tech Mono', monospace; } .mod-description { - color: var(--text-normal, #ccc); + color: var(--text-dim); font-size: 0.85rem; line-height: 1.5; word-wrap: break-word; @@ -1004,11 +1004,11 @@ select option { .mods-empty { text-align: center; - color: var(--text-dim, #888); + color: var(--text-dim); padding: 60px 30px; font-family: 'Share Tech Mono', monospace; font-size: 0.95rem; - background: rgba(0, 0, 0, 0.2); + background: var(--form-bg); border-radius: 12px; border: 2px dashed var(--primary-dim); margin: 10px 0; diff --git a/UIMod/onboard_bundled/assets/css/detectionmanager.css b/UIMod/onboard_bundled/assets/css/detectionmanager.css index 6bf80a88..21658fb6 100644 --- a/UIMod/onboard_bundled/assets/css/detectionmanager.css +++ b/UIMod/onboard_bundled/assets/css/detectionmanager.css @@ -1,13 +1,13 @@ @import '/static/css/variables.css'; #detection-list-container { - background: rgba(114, 137, 218, 0.1); + background: var(--discord-bg); } /* Detection list */ .detection-list { margin-top: 2rem; - border: 1px solid #ccc; + border: 1px solid var(--text-dim); border-radius: 4px; overflow: hidden; } @@ -18,7 +18,7 @@ display: grid; grid-template-columns: 100px 2fr 2fr 120px; gap: 1rem; - border-bottom: 1px solid #ccc; + border-bottom: 1px solid var(--text-dim); } .detection-item { @@ -26,7 +26,7 @@ display: grid; grid-template-columns: 100px 2fr 2fr 120px; gap: 1rem; - border-bottom: 1px solid #eee; + border-bottom: 1px solid var(--text-dim); align-items: center; } @@ -87,7 +87,7 @@ bottom: 4px; transition: .4s; border-radius: 50%; - background-color: white; + background-color: var(--text-header); } input:checked+.slider { @@ -109,25 +109,25 @@ input:checked+.slider:before { .type-keyword { background-color: var(--primary); - color: #0066cc; + color: var(--bg-dark); } .type-regex { background-color: var(--primary); - color: #fd7e14; + color: var(--bg-dark); } .empty-list { padding: 2rem; text-align: center; - color: #666; + color: var(--text-dim); font-style: italic; } /* Loading spinner */ .loader { - border: 5px solid #f3f3f3; - border-top: 5px solid #0066cc; + border: 5px solid var(--surface-dark); + border-top: 5px solid var(--accent); border-radius: 50%; width: 40px; height: 40px; @@ -153,7 +153,7 @@ input:checked+.slider:before { right: 20px; padding: 1rem; border-radius: 4px; - color: white; + color: var(--text-header); font-weight: bold; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); display: none; @@ -168,14 +168,14 @@ input:checked+.slider:before { } .notification-error { - background-color: #dc3546; + background-color: var(--danger); } .form-group input, .form-group textarea { width: 100%; padding: 0.75rem; - border: 1px solid #ccc; + border: 1px solid var(--text-dim); border-radius: 4px; box-sizing: border-box; background: var(--bg-dark); diff --git a/UIMod/onboard_bundled/assets/css/home.css b/UIMod/onboard_bundled/assets/css/home.css index 1578a958..5108525a 100644 --- a/UIMod/onboard_bundled/assets/css/home.css +++ b/UIMod/onboard_bundled/assets/css/home.css @@ -15,7 +15,7 @@ text-align: center; line-height: 2; padding: 10px; - background-color: rgba(0, 255, 171, 0.05); + background-color: var(--primary-bg-subtle); border-radius: 5px; border-left: 3px solid var(--primary); transition: opacity var(--transition-fast); @@ -27,8 +27,8 @@ top: 22px; font-family: 'Share Tech Mono', monospace; font-size: 0.8rem; - color: rgba(255, 255, 255, 0.75); - background-color: rgba(0, 0, 0, 0.35); + color: var(--text-dim); + background-color: var(--overlay-bg); padding: 2px 8px; border-radius: 4px; letter-spacing: 0.5px; @@ -48,14 +48,14 @@ } .status-indicator.online { - background-color: #4CAF50; + background-color: var(--success); animation: pulse 2s ease-in-out infinite; - box-shadow: 0 0 10px rgba(76, 175, 80, 0.7); + box-shadow: 0 0 10px color-mix(in srgb, var(--success) 70%, transparent); } .status-indicator.offline { - background-color: #F44336; - box-shadow: 0 0 10px rgba(244, 67, 54, 0.7); + background-color: var(--danger); + box-shadow: 0 0 10px color-mix(in srgb, var(--danger) 70%, transparent); } .status-indicator.offline::before, @@ -66,7 +66,7 @@ left: 50%; width: 10px; height: 2px; - background-color: #FFFFFF; + background-color: var(--text-header); } .status-indicator.offline::before { @@ -78,25 +78,25 @@ } .status-indicator.error { - background-color: #FFC107; - box-shadow: 0 0 10px rgba(255, 193, 7, 0.7); + background-color: var(--warning); + box-shadow: 0 0 10px color-mix(in srgb, var(--warning) 70%, transparent); animation: shake 0.5s ease-in-out infinite; } @keyframes pulse { 0% { transform: scale(1); - box-shadow: 0 0 10px rgba(76, 175, 80, 0.7); + box-shadow: 0 0 10px color-mix(in srgb, var(--success) 70%, transparent); } 50% { transform: scale(1.2); - box-shadow: 0 0 14px rgba(76, 175, 80, 0.9); + box-shadow: 0 0 14px color-mix(in srgb, var(--success) 90%, transparent); } 100% { transform: scale(1); - box-shadow: 0 0 10px rgba(76, 175, 80, 0.7); + box-shadow: 0 0 10px color-mix(in srgb, var(--success) 70%, transparent); } } @@ -123,7 +123,7 @@ padding: 20px; height: 400px; overflow-y: auto; - background-color: rgba(0, 0, 0, 0.85); + background-color: var(--overlay-bg-heavy); color: var(--primary); margin-bottom: 30px; border-radius: 8px; @@ -131,7 +131,7 @@ font-family: 'Share Tech Mono', 'Courier New', monospace; position: relative; scrollbar-width: thin; - scrollbar-color: var(--primary) #000; + scrollbar-color: var(--primary) var(--bg-dark); display: flex; flex-direction: column; } @@ -145,7 +145,7 @@ #console::-webkit-scrollbar-track, #detection-console::-webkit-scrollbar-track, #backendlog-console::-webkit-scrollbar-track { - background: #000; + background: var(--bg-dark); border-radius: 4px; } @@ -170,7 +170,7 @@ content: ''; position: absolute; inset: 0; - background: linear-gradient(transparent 50%, rgba(0, 255, 171, 0.03) 50%); + background: linear-gradient(transparent 50%, var(--primary-bg-subtle) 50%); background-size: 100% 4px; pointer-events: none; opacity: 0.3; @@ -181,7 +181,7 @@ margin: 10px 0; border-radius: 4px; border-left: 3px solid var(--primary); - background-color: rgba(0, 255, 171, 0.05); + background-color: var(--primary-bg-subtle); transition: all var(--transition-normal); word-wrap: break-word; } @@ -191,7 +191,7 @@ margin: 5px 0; border-radius: 4px; border-left: 3px solid var(--primary); - background-color: rgba(0, 255, 171, 0.05); + background-color: var(--primary-bg-subtle); transition: all var(--transition-normal); word-wrap: break-word; } @@ -205,12 +205,12 @@ } .detection-event:hover { - background-color: rgba(0, 255, 171, 0.1); + background-color: var(--primary-glow-soft); transform: translateX(3px); } .event-timestamp { - color: #888; + color: var(--text-muted); font-size: 0.9em; margin-right: 5px; } @@ -237,26 +237,26 @@ } .event-player-disconnect { - border-left-color: #FF7700; + border-left-color: var(--warning); } .event-world-saved { - border-left-color: #00FFFF; + border-left-color: var(--accent); } .event-exception { border-left-color: var(--danger); - background-color: rgba(255, 0, 0, 0.1); + background-color: color-mix(in srgb, var(--danger) 10%, transparent); } /* Backups */ #backups { position: relative; margin-top: 40px; - background-color: rgba(0, 255, 171, 0.05); + background-color: var(--primary-bg-subtle); padding: 20px; border-radius: 8px; - border: 1px solid rgba(0, 255, 171, 0.3); + border: 1px solid var(--primary-glow); transition: transform var(--transition-normal); } @@ -268,10 +268,10 @@ #players { position: relative; margin-top: 40px; - background-color: rgba(0, 255, 171, 0.05); + background-color: var(--primary-bg-subtle); padding: 20px; border-radius: 8px; - border: 1px solid rgba(0, 255, 171, 0.3); + border: 1px solid var(--primary-glow); transition: transform var(--transition-normal); } @@ -293,21 +293,21 @@ } .player-item { - background-color: rgba(0, 0, 0, 0.4); + background-color: var(--nav-bg); padding: 15px; margin-bottom: 15px; border-radius: 8px; display: flex; justify-content: space-between; align-items: center; - border: 2px solid rgba(0, 255, 171, 0.5); + border: 2px solid var(--primary-glow-strong); transition: all var(--transition-normal); line-height: 1.6; } .player-item:hover, .player-item.animate-in:hover { - background-color: rgba(0, 0, 0, 0.6); + background-color: var(--nav-bg-hover); border-color: var(--primary); transform: translateX(5px); } @@ -338,7 +338,7 @@ .player-name { font-size: 1.1rem; - color: #fff; + color: var(--text-header); } /* Backups */ @@ -371,23 +371,23 @@ #backupLimit { padding: 8px 12px; - background-color: rgba(0, 0, 0, 0.6); + background-color: var(--input-bg); color: var(--text-bright); - border: 1px solid rgba(0, 255, 171, 0.5); + border: 1px solid var(--primary-glow-strong); border-radius: 4px; font-family: 'Press Start 2P', cursive; font-size: 0.7rem; } .backup-item { - background-color: rgba(0, 0, 0, 0.4); + background-color: var(--nav-bg); padding: 20px; margin-bottom: 15px; border-radius: 12px; display: flex; justify-content: space-between; align-items: center; - border: 2px solid rgba(0, 255, 171, 0.3); + border: 2px solid var(--primary-glow); transition: all var(--transition-normal); position: relative; overflow: hidden; @@ -399,7 +399,7 @@ .backup-item:hover, .backup-item.animate-in:hover { - background-color: rgba(0, 0, 0, 0.6); + background-color: var(--nav-bg-hover); border-color: var(--primary); transform: translateX(5px); } @@ -430,15 +430,15 @@ } .backup-type.preterrain-trio { - background-color: rgba(255, 165, 0, 0.2); - color: #ffa500; - border: 1px solid rgba(255, 165, 0, 0.4); + background-color: color-mix(in srgb, var(--warning) 20%, transparent); + color: var(--warning); + border: 1px solid color-mix(in srgb, var(--warning) 40%, transparent); } .backup-type.dotsave { - background-color: rgba(0, 255, 171, 0.2); + background-color: var(--primary-bg-medium); color: var(--primary); - border: 1px solid rgba(0, 255, 171, 0.4); + border: 1px solid var(--primary-glow-medium); } .backup-date { @@ -456,7 +456,7 @@ .restore-btn, .download-btn { padding: 10px 18px; - background-color: rgba(0, 255, 171, 0.1); + background-color: var(--primary-glow-soft); color: var(--text-bright); border: 2px solid var(--primary); border-radius: 8px; @@ -470,7 +470,7 @@ .restore-btn:hover, .download-btn:hover { background-color: var(--primary); - color: #000; + color: var(--bg-dark); } .no-backups, @@ -479,9 +479,9 @@ padding: 40px; color: var(--text-dim); font-style: italic; - background-color: rgba(0, 0, 0, 0.2); + background-color: var(--form-bg); border-radius: 8px; - border: 1px dashed rgba(0, 255, 171, 0.3); + border: 1px dashed var(--primary-glow); } @keyframes slideIn { @@ -504,13 +504,13 @@ left: 20px; width: 60px; height: 60px; - background: linear-gradient(135deg, #ff6b6b, #ff4444); + background: linear-gradient(135deg, var(--danger), color-mix(in srgb, var(--danger) 80%, black)); border-radius: 50%; cursor: pointer; display: none; align-items: center; justify-content: center; - box-shadow: 0 4px 20px rgba(255, 68, 68, 0.5); + box-shadow: 0 4px 20px color-mix(in srgb, var(--danger) 50%, transparent); z-index: 9999; animation: bounce 2s ease-in-out infinite; transition: transform 0.2s ease; @@ -523,7 +523,7 @@ #update-indicator-float::before { content: "↑"; font-size: 32px; - color: white; + color: var(--text-header); font-weight: bold; animation: pulse-icon 1.5s ease-in-out infinite; } @@ -535,7 +535,7 @@ right: -5px; width: 20px; height: 20px; - background: #fff; + background: var(--text-header); border-radius: 50%; animation: ping 2s cubic-bezier(0, 0, 0.2, 1) infinite; } @@ -585,7 +585,7 @@ left: 0; width: 100%; height: 100%; - background: rgba(0, 0, 0, 0.8); + background: var(--overlay-bg-heavy); z-index: 10000; align-items: center; justify-content: center; @@ -596,13 +596,13 @@ } .update-modal-content { - background: linear-gradient(135deg, #2d2d44, #1a1a2e); - border: 3px solid #ff4444; + background: linear-gradient(135deg, var(--surface-hover), var(--bg-dark)); + border: 3px solid var(--danger); border-radius: 16px; padding: 40px; max-width: 500px; width: 90%; - box-shadow: 0 8px 40px rgba(255, 68, 68, 0.3); + box-shadow: 0 8px 40px color-mix(in srgb, var(--danger) 30%, transparent); position: relative; animation: modalSlideIn 0.3s ease-out; } @@ -625,7 +625,7 @@ right: 15px; background: transparent; border: none; - color: #888; + color: var(--text-muted); font-size: 28px; cursor: pointer; width: 35px; @@ -639,38 +639,38 @@ .update-modal-close:hover { background: rgba(255, 255, 255, 0.1); - color: #fff; + color: var(--text-header); } .update-modal-icon { width: 80px; height: 80px; margin: 0 auto 20px; - background: linear-gradient(135deg, #ff6b6b, #ff4444); + background: linear-gradient(135deg, var(--danger), color-mix(in srgb, var(--danger) 80%, black)); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 48px; - color: white; + color: var(--text-header); } .update-modal-content h2 { - color: #fff; + color: var(--text-header); margin: 0 0 15px 0; text-align: center; font-size: 24px; } .update-modal-content p { - color: #ccc; + color: var(--text-dim); text-align: center; margin: 0 0 10px 0; line-height: 1.6; } .update-version { - color: #ff6b6b; + color: var(--danger); font-weight: bold; font-size: 20px; text-align: center; @@ -695,24 +695,24 @@ } #update-now-btn { - background: linear-gradient(135deg, #4CAF50, #45a049); - color: white; + background: linear-gradient(135deg, var(--success), color-mix(in srgb, var(--success) 90%, black)); + color: var(--text-header); } #update-now-btn:hover { transform: translateY(-2px); - box-shadow: 0 4px 15px rgba(76, 175, 80, 0.4); + box-shadow: 0 4px 15px color-mix(in srgb, var(--success) 40%, transparent); } #update-later-btn { background: rgba(255, 255, 255, 0.1); - color: #ccc; + color: var(--text-dim); border: 2px solid rgba(255, 255, 255, 0.2); } #update-later-btn:hover { background: rgba(255, 255, 255, 0.15); - color: #fff; + color: var(--text-header); } /* Update Status Messages in Modal */ @@ -727,23 +727,23 @@ .update-status-message.running { display: block; - background: rgba(33, 150, 243, 0.2); - border: 2px solid #2196F3; - color: #2196F3; + background: color-mix(in srgb, var(--accent) 20%, transparent); + border: 2px solid var(--accent); + color: var(--accent); } .update-status-message.success { display: block; - background: rgba(76, 175, 80, 0.2); - border: 2px solid #4CAF50; - color: #4CAF50; + background: color-mix(in srgb, var(--success) 20%, transparent); + border: 2px solid var(--success); + color: var(--success); } .update-status-message.failed { display: block; - background: rgba(255, 68, 68, 0.2); - border: 2px solid #ff4444; - color: #ff4444; + background: color-mix(in srgb, var(--danger) 20%, transparent); + border: 2px solid var(--danger); + color: var(--danger); } #update-button { @@ -766,7 +766,7 @@ display: none; margin-top: 20px; font-weight: bold; - color: #fff; + color: var(--text-header); } .update-status-message.running { @@ -780,8 +780,8 @@ right: 45px; width: 32px; height: 32px; - background: #F44336; - box-shadow: 0 0 10px rgba(244, 67, 54, 0.7); + background: var(--danger); + box-shadow: 0 0 10px color-mix(in srgb, var(--danger) 70%, transparent); border: none; cursor: pointer; padding: 0; @@ -792,6 +792,6 @@ } .update-icon:hover { - background: #F44336; + background: var(--danger); transform: scale(1.1); } \ No newline at end of file diff --git a/UIMod/onboard_bundled/assets/css/info-notice.css b/UIMod/onboard_bundled/assets/css/info-notice.css index ebcd7b3b..1a090ef3 100644 --- a/UIMod/onboard_bundled/assets/css/info-notice.css +++ b/UIMod/onboard_bundled/assets/css/info-notice.css @@ -1,11 +1,11 @@ .info-notice { - border: 1px solid #4a90e2; + border: 1px solid var(--accent); border-radius: 8px; padding: 15px; margin: 15px 0; - background: rgba(74, 144, 226, 0.1); - color: #e0e0e0; - box-shadow: 0 2px 8px rgba(74, 144, 226, 0.2); + background: color-mix(in srgb, var(--accent) 10%, transparent); + color: var(--text-bright); + box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 20%, transparent); } .info-notice h3 { @@ -14,7 +14,7 @@ display: flex; align-items: center; gap: 8px; - color: #4a90e2; + color: var(--accent); cursor: pointer; } @@ -44,12 +44,12 @@ } .info-notice a { - color: #4a90e2; + color: var(--accent); text-decoration: underline; } .info-notice a:hover { - color: #7bb3f0; + color: color-mix(in srgb, var(--accent) 70%, white); } .notice-icon { @@ -58,13 +58,13 @@ } .update { - border: 1px solid #af534c; + border: 1px solid color-mix(in srgb, var(--danger) 70%, black); border-radius: 8px; padding: 12px; margin: 10px 0; - background: #784a47; - color: #c8e6c9; - box-shadow: 0 2px 6px rgba(76, 175, 80, 0.2); + background: color-mix(in srgb, var(--danger) 30%, var(--bg-dark)); + color: var(--text-bright); + box-shadow: 0 2px 6px color-mix(in srgb, var(--success) 20%, transparent); } .update h3 { @@ -73,7 +73,7 @@ display: flex; align-items: center; gap: 6px; - color: #4caf50; + color: var(--success); } .update p { @@ -83,12 +83,12 @@ } .status-good { - color: #4caf50; + color: var(--success); font-weight: 600; } .status-bad { - color: #f44336; + color: var(--danger); font-weight: 600; } diff --git a/UIMod/onboard_bundled/assets/css/popup.css b/UIMod/onboard_bundled/assets/css/popup.css index cdf64cb2..4bae180d 100644 --- a/UIMod/onboard_bundled/assets/css/popup.css +++ b/UIMod/onboard_bundled/assets/css/popup.css @@ -38,44 +38,44 @@ .popup-content button { margin-top: 15px; padding: 10px 20px; - color: white; + color: var(--text-header); border: none; border-radius: 3px; cursor: pointer; } .popup.error .popup-content { - border-left: 2px solid #ff4d4d; + border-left: 2px solid var(--danger); } .popup.error button { - background-color: #ff4d4d; + background-color: var(--danger); } .popup.error button:hover { - background-color: #e60000; + background-color: color-mix(in srgb, var(--danger) 80%, black); } .popup.success .popup-content { - border-left: 2px solid #28a745; + border-left: 2px solid var(--success); } .popup.success button { - background-color: #28a745; + background-color: var(--success); } .popup.success button:hover { - background-color: #218838; + background-color: color-mix(in srgb, var(--success) 80%, black); } .popup.info .popup-content { - border-left: 2px solid #17a2b8; + border-left: 2px solid var(--accent); } .popup.info button { - background-color: #17a2b8; + background-color: var(--accent); } .popup.info button:hover { - background-color: #138496; + background-color: color-mix(in srgb, var(--accent) 80%, black); } \ No newline at end of file diff --git a/UIMod/onboard_bundled/assets/css/sscm.css b/UIMod/onboard_bundled/assets/css/sscm.css index 4050fc57..7b647837 100644 --- a/UIMod/onboard_bundled/assets/css/sscm.css +++ b/UIMod/onboard_bundled/assets/css/sscm.css @@ -39,7 +39,7 @@ #sscm-command-input:disabled { background: rgba(255, 255, 255, 0.1); - color: var(--text-bright, #ffffff); + color: var(--text-bright); opacity: 0.7; cursor: not-allowed; } @@ -56,7 +56,7 @@ right: 10px; max-height: 250px; overflow-y: auto; - background: var(--bg-dark, #2d333b); + background: var(--bg-dark); border-radius: 6px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); z-index: 1000; @@ -68,7 +68,7 @@ display: flex; align-items: flex-start; padding: 10px 14px; - color: var(--text-bright, #ffffff); + color: var(--text-bright); cursor: pointer; transition: all 0.2s ease; gap: 10px; @@ -76,8 +76,8 @@ .sscm-suggestion-item:hover, .sscm-suggestion-item.highlighted { - background: var(--primary-glow, #3b82f6); - color: #ffffff; + background: var(--primary-glow); + color: var(--text-header); } .sscm-suggestion-name { @@ -87,7 +87,7 @@ } .sscm-suggestion-params { - color: var(--text-muted, #d1d5db); + color: var(--text-bright); flex: 0 0 250px; overflow-wrap: break-word; line-height: 1.3; @@ -96,7 +96,7 @@ } .sscm-suggestion-desc { - color: var(--text-dim, #9ca3af); + color: var(--text-dim); flex: 1; overflow-wrap: break-word; hyphens: auto; diff --git a/UIMod/onboard_bundled/assets/css/theme-editor.css b/UIMod/onboard_bundled/assets/css/theme-editor.css new file mode 100644 index 00000000..c77bf9fc --- /dev/null +++ b/UIMod/onboard_bundled/assets/css/theme-editor.css @@ -0,0 +1,242 @@ +@import '/static/css/variables.css'; + + +.theme-editor { + padding: 20px; +} + +.theme-editor-section { + margin-bottom: 30px; + padding: 20px; + background: var(--form-bg); + border-radius: 8px; + border: 1px solid var(--primary-dim); +} + +.theme-editor-section h3 { + margin: 0 0 15px 0; + padding-bottom: 10px; + border-bottom: 2px solid var(--primary-dim); + color: var(--text-bright); + font-family: 'Press Start 2P', cursive; + font-size: 0.85rem; + letter-spacing: 1px; +} + +.theme-color-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + gap: 18px; +} + +.theme-color-item { + display: flex; + flex-direction: column; + gap: 6px; +} + +.theme-color-item label { + font-family: 'Share Tech Mono', monospace; + font-size: 0.85rem; + color: var(--text-bright); + display: flex; + align-items: center; + gap: 8px; +} + +.theme-color-item .color-input-wrapper { + display: flex; + align-items: center; + gap: 8px; +} + +.theme-color-item input[type="color"] { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + width: 42px; + height: 42px; + border: 2px solid var(--primary-dim); + border-radius: 6px; + cursor: pointer; + background: transparent; + padding: 2px; + transition: border-color var(--transition-fast); +} + +.theme-color-item input[type="color"]:hover { + border-color: var(--primary); +} + +.theme-color-item input[type="color"]::-webkit-color-swatch-wrapper { + padding: 0; +} + +.theme-color-item input[type="color"]::-webkit-color-swatch { + border: none; + border-radius: 3px; +} + +.theme-color-item input[type="color"]::-moz-color-swatch { + border: none; + border-radius: 3px; +} + +.theme-color-item input[type="text"].color-hex-input { + width: 100px; + padding: 8px 10px; + font-family: 'Share Tech Mono', monospace; + font-size: 0.85rem; + background: var(--input-bg); + color: var(--primary); + border: 2px solid var(--primary-dim); + border-radius: 4px; + text-transform: uppercase; + margin: 0; +} + +.theme-color-item input[type="text"].color-hex-input:focus { + border-color: var(--primary); + box-shadow: 0 0 8px var(--primary-glow); + outline: none; +} + +.theme-color-item .color-description { + font-size: 0.75rem; + color: var(--text-dim); + font-style: italic; +} + +/* Preset Themes */ +.theme-presets { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 20px; +} + +.theme-preset-btn { + display: flex; + align-items: center; + gap: 8px; + padding: 10px 16px; + background: var(--tab-bg); + border: 2px solid var(--primary-dim); + border-radius: 8px; + color: var(--text-bright); + cursor: pointer; + font-family: 'Share Tech Mono', monospace; + font-size: 0.85rem; + transition: all var(--transition-normal); +} + +.theme-preset-btn:hover { + border-color: var(--primary); + transform: translateY(-2px); + box-shadow: 0 4px 12px var(--primary-glow); +} + +.theme-preset-btn.active { + background: var(--primary-bg-medium); + border-color: var(--primary); + box-shadow: 0 0 15px var(--primary-glow); +} + +.theme-preset-colors { + display: flex; + gap: 3px; +} + +.theme-preset-swatch { + width: 14px; + height: 14px; + border-radius: 50%; + border: 1px solid rgba(255, 255, 255, 0.2); +} + +/* Theme Actions */ +.theme-actions { + display: flex; + gap: 12px; + margin-top: 20px; + flex-wrap: wrap; +} + +.theme-actions button { + padding: 10px 20px; + font-size: 0.85rem; +} + +/* Live Preview */ +.theme-preview-strip { + display: flex; + gap: 8px; + padding: 12px; + background: var(--bg-dark); + border-radius: 8px; + border: 1px solid var(--primary-dim); + margin-top: 15px; + flex-wrap: wrap; + align-items: center; +} + +.preview-swatch { + width: 32px; + height: 32px; + border-radius: 6px; + border: 2px solid rgba(255, 255, 255, 0.15); + position: relative; + transition: transform var(--transition-fast); +} + +.preview-swatch:hover { + transform: scale(1.15); +} + +.preview-swatch-label { + font-size: 0.7rem; + color: var(--text-dim); + text-align: center; + margin-top: 2px; + font-family: 'Share Tech Mono', monospace; +} + +.preview-swatch-group { + display: flex; + flex-direction: column; + align-items: center; + gap: 2px; +} + +/* Import/Export */ +.theme-import-export { + display: flex; + gap: 10px; + align-items: center; + flex-wrap: wrap; +} + +.theme-import-export textarea { + width: 100%; + min-height: 60px; + padding: 10px; + font-family: 'Share Tech Mono', monospace; + font-size: 0.8rem; + background: var(--input-bg); + color: var(--primary); + border: 2px solid var(--primary-dim); + border-radius: 6px; + resize: vertical; +} + +.theme-import-export textarea:focus { + border-color: var(--primary); + box-shadow: 0 0 8px var(--primary-glow); + outline: none; +} + +/* Notification info type (not in detectionmanager.css) */ +.notification-info { + background-color: var(--accent); + color: var(--text-header); +} diff --git a/UIMod/onboard_bundled/assets/css/variables.css b/UIMod/onboard_bundled/assets/css/variables.css index 85d81679..faaa007a 100644 --- a/UIMod/onboard_bundled/assets/css/variables.css +++ b/UIMod/onboard_bundled/assets/css/variables.css @@ -1,59 +1,91 @@ :root { - /* Colors */ - --primary: - #00FFAB; - --primary-dim: rgba(0, 255, 171, 0.7); - --primary-glow: rgba(0, 255, 171, 0.3); - --bg-dark: - #0a0a14; - --bg-panel: #1b1b2f8f; - --accent: - #0084ff; - --text-bright: - #e0ffe9; - --text-header: - #ffffff; - --danger: - #ff3860; - --success: - #48c774; - --warning: - #ffdd57; - - /* Transitions */ + /* ═══════════════════════════════════════════ + SSUI Theme Variables + These are the user-customizable theme values. + Override via localStorage theme system. + ═══════════════════════════════════════════ + + ── Core Colors ── */ + --primary: #00FFAB; /* Main accent / brand color */ + --bg-dark: #0a0a14; /* Page background */ + --bg-panel: #1b1b2f8f; /* Panel/card backgrounds */ + --accent: #0084ff; /* Secondary accent (links, badges) */ + --danger: #ff3860; /* Errors, destructive actions */ + --success: #48c774; /* Success states */ + --warning: #ffdd57; /* Warnings */ + + /* ── Text Colors ── */ + --text-header: #ffffff; /* Headings, bright text */ + --text-bright: #e0ffe9; /* Primary readable text */ + --text-dim: #aaaaaa; /* Subdued text, hints, descriptions */ + --text-muted: #888888; /* Timestamps, least-important text */ + + /* ── Surface Colors ── */ + --surface-dark: #232338; /* Button backgrounds, elevated surfaces */ + --surface-hover: #333350; /* Hover state for surfaces */ + --surface-overlay: #1b1b2f; /* Dropdowns, overlays */ + + /* ── Discord (brand, not themeable) ── */ + --discord-accent: #7289da; + + /* ── Transitions ── */ --transition-fast: 0.2s ease; --transition-normal: 0.3s ease; --transition-slow: 0.5s ease; - /* 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); + + /* ═══════════════════════════════════════════ + Derived Variables (computed from core colors) + Users don't set these directly — they auto-derive. + ═══════════════════════════════════════════ */ + + /* Primary alpha variants */ + --primary-dim: color-mix(in srgb, var(--primary) 70%, transparent); + --primary-glow: color-mix(in srgb, var(--primary) 30%, transparent); + --primary-glow-strong: color-mix(in srgb, var(--primary) 50%, transparent); + --primary-glow-soft: color-mix(in srgb, var(--primary) 10%, transparent); + --primary-glow-medium: color-mix(in srgb, var(--primary) 40%, transparent); + --primary-glow-intense: color-mix(in srgb, var(--primary) 70%, transparent); + --primary-bg-subtle: color-mix(in srgb, var(--primary) 5%, transparent); + --primary-bg-light: color-mix(in srgb, var(--primary) 15%, transparent); + --primary-bg-medium: color-mix(in srgb, var(--primary) 20%, transparent); + + /* Surface with transparency */ --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); + --form-bg: rgba(0, 0, 0, 0.2); --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; + --overlay-bg: rgba(0, 0, 0, 0.3); + --overlay-bg-heavy: rgba(0, 0, 0, 0.8); + + /* Discord derived */ + --discord-bg: color-mix(in srgb, var(--discord-accent) 10%, transparent); + --discord-border: color-mix(in srgb, var(--discord-accent) 50%, transparent); + --discord-glow: color-mix(in srgb, var(--discord-accent) 30%, transparent); + + /* ── Legacy aliases (mapped to new vars for compatibility) ── */ + --button-bg: var(--surface-dark); + --button-bg-hover: var(--surface-hover); + --button-glow: var(--primary-glow-medium); + --button-glow-strong: var(--primary-glow-intense); + --button-glow-soft: var(--primary-glow-soft); + --button-glow-stronger: var(--primary-glow-strong); + --submit-bg: var(--primary-bg-medium); + --submit-hover-text: #000; + --tab-hover-bg: var(--primary-glow-soft); + --tab-active-bg: var(--primary-bg-medium); + --tab-active-glow: var(--primary-glow-strong); + --wizard-bg: var(--primary-bg-light); + --wizard-glow: var(--primary-glow); + --wizard-glow-strong: color-mix(in srgb, var(--primary) 60%, transparent); + --nav-border: var(--primary-glow-strong); + --select-bg-hover: var(--overlay-bg-heavy); + --option-bg: var(--surface-overlay); + + /* Console colors (used by JS) */ + --console-info: #0af; + --console-warning: #ff0; + --console-error: #ff3333; + --console-success: #0f0; + --console-boot: #0f0; } \ 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 4c65fdd2..a7df2649 100644 --- a/UIMod/onboard_bundled/assets/js/console-manager.js +++ b/UIMod/onboard_bundled/assets/js/console-manager.js @@ -104,6 +104,7 @@ function handleConsole() { "Welcome home, Sir!" ]; + const cssVar = (name) => getComputedStyle(document.documentElement).getPropertyValue(name).trim(); const addMessage = (text, color, style = 'normal') => { const div = document.createElement('div'); div.textContent = text; @@ -162,13 +163,13 @@ function handleConsole() { typeTextWithCallback(consoleElement, bootTitle, 30, () => { // Show two funny messages while connecting const messageIndex1 = Math.floor(Math.random() * funMessages.length); - addMessage(funMessages[messageIndex1], '#0af', 'italic'); + addMessage(funMessages[messageIndex1], cssVar('--console-info'), 'italic'); let messageIndex2; do { messageIndex2 = Math.floor(Math.random() * funMessages.length); } while (messageIndex2 === messageIndex1); - addMessage(funMessages[messageIndex2], '#0af', 'italic'); + addMessage(funMessages[messageIndex2], cssVar('--console-info'), 'italic'); // Set up the persistent console stream outputEventSource = new EventSource('/console'); @@ -191,7 +192,7 @@ function handleConsole() { console.error("Console stream disconnected"); outputEventSource.close(); outputEventSource = null; - addMessage("Warning: Console stream unavailable. Retrying...", '#ff0'); + addMessage("Warning: Console stream unavailable. Retrying...", cssVar('--console-warning')); if (window.location.pathname === '/') { setTimeout(() => { if (!outputEventSource) { @@ -206,9 +207,9 @@ function handleConsole() { function finishInitialization() { if (bugChance < 0.05) { - addMessage(bugMessage, 'red'); + addMessage(bugMessage, cssVar('--console-error')); setTimeout(() => { - addMessage("Repair complete. Continuing initialization...", 'green'); + addMessage("Repair complete. Continuing initialization...", cssVar('--console-success')); completeBoot(); }, 1000); } else { @@ -219,7 +220,7 @@ function handleConsole() { function completeBoot() { setTimeout(() => { createCommandInput(); // Add input after boot - addMessage(bootCompleteMessage, '#0f0'); + addMessage(bootCompleteMessage, cssVar('--console-success')); //addMessage("StationeersServerUI is becoming SteamServerUI!", '#ff4500'); //addMessage("Please mind the New Terrain System warning below", '#ff4500'); consoleElement.scrollTop = consoleElement.scrollHeight; diff --git a/UIMod/onboard_bundled/assets/js/slp.js b/UIMod/onboard_bundled/assets/js/slp.js index 8f9ea091..f4588d19 100644 --- a/UIMod/onboard_bundled/assets/js/slp.js +++ b/UIMod/onboard_bundled/assets/js/slp.js @@ -185,7 +185,7 @@ function updateFileDisplay() { uploadZone.innerHTML = '' + '
File Selected
' + '
' + selectedModFile.name + '
' + - '
' + (selectedModFile.size / 1024 / 1024).toFixed(2) + ' MB
'; + '
' + (selectedModFile.size / 1024 / 1024).toFixed(2) + ' MB
'; uploadBtn.disabled = false; uploadBtn.style.opacity = '1'; } else { diff --git a/UIMod/onboard_bundled/assets/js/theme-editor.js b/UIMod/onboard_bundled/assets/js/theme-editor.js new file mode 100644 index 00000000..fd0d0dcf --- /dev/null +++ b/UIMod/onboard_bundled/assets/js/theme-editor.js @@ -0,0 +1,278 @@ +/** + * SSUI Theme Editor + * Renders the theme editing UI inside the theme config tab. + * Depends on SSUITheme (theme-engine.js) being loaded first. + */ + +(function () { + 'use strict'; + + function renderThemeEditor() { + const container = document.getElementById('theme-editor-root'); + if (!container) return; + + const currentTheme = SSUITheme.getCurrentTheme(); + + // Group variables by their group + const groups = {}; + SSUITheme.THEME_VARS.forEach(v => { + if (!groups[v.group]) groups[v.group] = []; + groups[v.group].push(v); + }); + + let html = ''; + + // ── Preset Buttons ── + html += '
'; + html += '

Theme Presets

'; + html += '
'; + Object.entries(SSUITheme.PRESETS).forEach(([name, preset]) => { + const swatches = [preset['--primary'], preset['--bg-dark'], preset['--accent'], preset['--danger'], preset['--success']]; + html += ``; + }); + html += '
'; + html += '
'; + + // ── Color Editors per Group ── + Object.entries(groups).forEach(([groupName, vars]) => { + html += `
`; + html += `

${groupName}

`; + html += `
`; + vars.forEach(v => { + const val = currentTheme[v.variable] || '#000000'; + // Normalize to hex for the color picker + const hexVal = toHex(val); + html += `
`; + html += ` `; + html += `
`; + html += ` `; + html += ` `; + html += `
`; + html += ` ${v.description}`; + html += `
`; + }); + html += `
`; + html += `
`; + }); + + // ── Preview Strip ── + html += `
`; + html += `

Live Preview

`; + html += `
`; + SSUITheme.THEME_VARS.filter(v => v.group !== 'Console Colors').forEach(v => { + html += `
`; + html += `
`; + html += ` ${v.label}`; + html += `
`; + }); + html += `
`; + html += `
`; + + // ── Actions ── + html += `
`; + html += `

Actions

`; + html += `
`; + html += ` `; + html += ` `; + html += ` `; + html += ` `; + html += `
`; + + // Import area (hidden by default) + html += ``; + + // Export area (hidden by default) + html += ``; + + html += `
`; + + container.innerHTML = html; + } + + // ── Color conversion helpers ── + + function toHex(colorStr) { + if (!colorStr) return '#000000'; + colorStr = colorStr.trim(); + + // Already hex + if (/^#[0-9a-f]{6}$/i.test(colorStr)) return colorStr; + if (/^#[0-9a-f]{3}$/i.test(colorStr)) { + return '#' + colorStr[1] + colorStr[1] + colorStr[2] + colorStr[2] + colorStr[3] + colorStr[3]; + } + // 8-char hex with alpha — just take RGB + if (/^#[0-9a-f]{8}$/i.test(colorStr)) return colorStr.slice(0, 7); + + // rgb/rgba + const rgbMatch = colorStr.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/); + if (rgbMatch) { + const r = parseInt(rgbMatch[1]).toString(16).padStart(2, '0'); + const g = parseInt(rgbMatch[2]).toString(16).padStart(2, '0'); + const b = parseInt(rgbMatch[3]).toString(16).padStart(2, '0'); + return `#${r}${g}${b}`; + } + + // Named colors — use a canvas to resolve + try { + const ctx = document.createElement('canvas').getContext('2d'); + ctx.fillStyle = colorStr; + return ctx.fillStyle; // returns hex + } catch { + return '#000000'; + } + } + + // ── Event Handlers (global scope for inline onclick) ── + + window.onThemeColorChange = function (input) { + const varName = input.dataset.var; + const value = input.value; + document.documentElement.style.setProperty(varName, value); + // Sync hex text input + const hexInput = input.parentElement.querySelector('.color-hex-input'); + if (hexInput) hexInput.value = value; + }; + + window.onThemeHexChange = function (input) { + const varName = input.dataset.var; + let value = input.value.trim(); + // Validate hex + if (/^#[0-9a-f]{3,8}$/i.test(value)) { + document.documentElement.style.setProperty(varName, value); + // Sync color picker + const colorInput = input.parentElement.querySelector('input[type="color"]'); + if (colorInput) colorInput.value = toHex(value); + } + }; + + window.applyPresetTheme = function (presetName) { + const preset = SSUITheme.PRESETS[presetName]; + if (!preset) return; + SSUITheme.applyTheme(preset); + SSUITheme.saveTheme(preset); + // Re-render to update inputs + renderThemeEditor(); + showThemeNotification('Theme "' + presetName + '" applied and saved!', 'success'); + }; + + window.saveCurrentTheme = function () { + const theme = SSUITheme.getCurrentTheme(); + SSUITheme.saveTheme(theme); + showThemeNotification('Theme saved to browser storage!', 'success'); + }; + + window.resetToDefaults = function () { + SSUITheme.clearTheme(); + renderThemeEditor(); + showThemeNotification('Theme reset to defaults.', 'info'); + }; + + window.exportCurrentTheme = function () { + const area = document.getElementById('theme-export-area'); + const text = document.getElementById('theme-export-text'); + if (area && text) { + text.value = SSUITheme.exportTheme(); + area.style.display = 'block'; + } + // hide import if open + const imp = document.getElementById('theme-import-area'); + if (imp) imp.style.display = 'none'; + }; + + window.hideExportTheme = function () { + const area = document.getElementById('theme-export-area'); + if (area) area.style.display = 'none'; + }; + + window.copyExportedTheme = function () { + const text = document.getElementById('theme-export-text'); + if (text) { + navigator.clipboard.writeText(text.value).then(() => { + showThemeNotification('Theme JSON copied to clipboard!', 'success'); + }).catch(() => { + // Fallback + showThemeNotification('Theme copy failed!', 'error'); + }); + } + }; + + window.showImportTheme = function () { + const area = document.getElementById('theme-import-area'); + if (area) area.style.display = 'block'; + // hide export if open + const exp = document.getElementById('theme-export-area'); + if (exp) exp.style.display = 'none'; + }; + + window.hideImportTheme = function () { + const area = document.getElementById('theme-import-area'); + if (area) area.style.display = 'none'; + }; + + window.doImportTheme = function () { + const text = document.getElementById('theme-import-text'); + if (!text || !text.value.trim()) { + showThemeNotification('Please paste a theme JSON first.', 'error'); + return; + } + if (SSUITheme.importTheme(text.value.trim())) { + renderThemeEditor(); + showThemeNotification('Theme imported and applied!', 'success'); + } else { + showThemeNotification('Invalid theme JSON. Please check the format.', 'error'); + } + }; + + function showThemeNotification(message, type) { + // Reuse existing notification element or create a temporary one + let notif = document.getElementById('theme-notification'); + if (!notif) { + notif = document.createElement('div'); + notif.id = 'theme-notification'; + notif.className = 'notification'; + notif.style.position = 'fixed'; + notif.style.top = '20px'; + notif.style.right = '20px'; + notif.style.zIndex = '9999'; + notif.style.maxWidth = '350px'; + document.body.appendChild(notif); + } + notif.className = 'notification notification-' + type; + notif.textContent = message; + notif.style.display = 'block'; + clearTimeout(notif._timer); + notif._timer = setTimeout(() => { + notif.style.display = 'none'; + }, 3000); + } + + // Initialize when DOM is ready + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', renderThemeEditor); + } else { + renderThemeEditor(); + } +})(); diff --git a/UIMod/onboard_bundled/assets/js/theme-engine.js b/UIMod/onboard_bundled/assets/js/theme-engine.js new file mode 100644 index 00000000..1f1c71df --- /dev/null +++ b/UIMod/onboard_bundled/assets/js/theme-engine.js @@ -0,0 +1,511 @@ +/** + * SSUI Theme Engine + * Manages user-customizable themes via CSS variables and localStorage. + */ + +const SSUITheme = (() => { + const STORAGE_KEY = 'ssui-theme'; + + // ── Themeable variables ── + // Each entry: { variable, label, description, group } + const THEME_VARS = [ + // Core Colors + { variable: '--primary', label: 'Primary', description: 'Main accent / brand color', group: 'Core Colors' }, + { variable: '--bg-dark', label: 'Background', description: 'Page background color', group: 'Core Colors' }, + { variable: '--bg-panel', label: 'Panel BG', description: 'Panel / card background', group: 'Core Colors' }, + { variable: '--accent', label: 'Accent', description: 'Secondary accent (links, badges)', group: 'Core Colors' }, + { variable: '--danger', label: 'Danger', description: 'Errors, destructive actions', group: 'Core Colors' }, + { variable: '--success', label: 'Success', description: 'Success states', group: 'Core Colors' }, + { variable: '--warning', label: 'Warning', description: 'Warning states', group: 'Core Colors' }, + // Text + { variable: '--text-header', label: 'Header Text', description: 'Headings, bright text', group: 'Text Colors' }, + { variable: '--text-bright', label: 'Bright Text', description: 'Primary readable text', group: 'Text Colors' }, + { variable: '--text-dim', label: 'Dim Text', description: 'Subdued text, hints', group: 'Text Colors' }, + { variable: '--text-muted', label: 'Muted Text', description: 'Timestamps, least-important', group: 'Text Colors' }, + // Surfaces + { variable: '--surface-dark', label: 'Surface', description: 'Button / elevated backgrounds', group: 'Surfaces' }, + { variable: '--surface-hover', label: 'Surface Hover', description: 'Hover state for surfaces', group: 'Surfaces' }, + { variable: '--surface-overlay', label: 'Overlay', description: 'Dropdowns, overlays', group: 'Surfaces' }, + // Console + { variable: '--console-info', label: 'Info', description: 'Informational console messages', group: 'Console Colors' }, + { variable: '--console-warning', label: 'Warning', description: 'Warning console messages', group: 'Console Colors' }, + { variable: '--console-error', label: 'Error', description: 'Error console messages', group: 'Console Colors' }, + { variable: '--console-success', label: 'Success', description: 'Success / boot complete messages',group: 'Console Colors' }, + ]; + + // ── Preset Themes ── + const PRESETS = { + 'StationeersServerUI (default)': { + '--primary': '#00FFAB', + '--bg-dark': '#0a0a14', + '--bg-panel': '#1b1b2f8f', + '--accent': '#0084ff', + '--danger': '#ff3860', + '--success': '#48c774', + '--warning': '#ffdd57', + '--text-header': '#ffffff', + '--text-bright': '#e0ffe9', + '--text-dim': '#aaaaaa', + '--text-muted': '#888888', + '--surface-dark': '#232338', + '--surface-hover': '#333350', + '--surface-overlay': '#1b1b2f', + '--console-info': '#0af', + '--console-warning': '#ff0', + '--console-error': '#ff3333', + '--console-success': '#0f0', + }, + 'Neon Blue': { + '--primary': '#00D4FF', + '--bg-dark': '#080818', + '--bg-panel': '#12122a8f', + '--accent': '#7B68EE', + '--danger': '#FF4466', + '--success': '#00E676', + '--warning': '#FFD740', + '--text-header': '#FFFFFF', + '--text-bright': '#D0F0FF', + '--text-dim': '#8899AA', + '--text-muted': '#667788', + '--surface-dark': '#1A1A3E', + '--surface-hover': '#2A2A55', + '--surface-overlay': '#15152D', + '--console-info': '#00D4FF', + '--console-warning': '#FFD740', + '--console-error': '#FF4466', + '--console-success': '#00E676', + }, + 'Hot Pink': { + '--primary': '#FF1493', + '--bg-dark': '#0A0008', + '--bg-panel': '#1E0A1A8f', + '--accent': '#9B59B6', + '--danger': '#FF3030', + '--success': '#00E5A0', + '--warning': '#FFD700', + '--text-header': '#FFFFFF', + '--text-bright': '#FFD0E8', + '--text-dim': '#AA7799', + '--text-muted': '#886688', + '--surface-dark': '#2A1025', + '--surface-hover': '#3A1A35', + '--surface-overlay': '#1E0A18', + '--console-info': '#FF69B4', + '--console-warning': '#FFD700', + '--console-error': '#FF3030', + '--console-success': '#00E5A0', + }, + 'Midnight Purple': { + '--primary': '#B388FF', + '--bg-dark': '#08061A', + '--bg-panel': '#1A1040ef', + '--accent': '#82B1FF', + '--danger': '#FF5252', + '--success': '#69F0AE', + '--warning': '#FFD740', + '--text-header': '#FFFFFF', + '--text-bright': '#E0D0FF', + '--text-dim': '#9988BB', + '--text-muted': '#776699', + '--surface-dark': '#1E1440', + '--surface-hover': '#2E2060', + '--surface-overlay': '#160E30', + '--console-info': '#82B1FF', + '--console-warning': '#FFD740', + '--console-error': '#FF5252', + '--console-success': '#69F0AE', + }, + 'Colourblind friendly': { + '--primary': '#ffb300', + '--bg-dark': '#121212', + '--bg-panel': '#1e1e1e', + '--accent': '#ffb300', + '--danger': '#ff3b3b', + '--success': '#66d020', + '--warning': '#ffdd00', + '--text-header': '#ffffff', + '--text-bright': '#ffffff', + '--text-dim': '#bfbfbf', + '--text-muted': '#999999', + '--surface-dark': '#2a2a2a', + '--surface-hover': '#383838', + '--surface-overlay': '#1e1e1e', + '--console-info': '#ffb300', + '--console-warning': '#ffdd00', + '--console-error': '#ff3b3b', + '--console-success': '#66d020', + }, + 'Tynningö': { + '--primary': '#6a9955', + '--bg-dark': '#1e1e1e', + '--bg-panel': '#252526', + '--accent': '#6a9955', + '--danger': '#ff3860', + '--success': '#6a9955', + '--warning': '#ce9178', + '--text-header': '#d4d4d4', + '--text-bright': '#d4d4d4', + '--text-dim': '#a9a9a9', + '--text-muted': '#808080', + '--surface-dark': '#2d2d2d', + '--surface-hover': '#3c3c3c', + '--surface-overlay': '#252526', + '--console-info': '#6a9955', + '--console-warning': '#ce9178', + '--console-error': '#ff3860', + '--console-success': '#6a9955', + }, + 'Dammstakärret': { + '--primary': '#7a9a7a', + '--bg-dark': '#121a12', + '--bg-panel': '#1b2a1b', + '--accent': '#7a9a7a', + '--danger': '#ff6b6b', + '--success': '#7a9a7a', + '--warning': '#c9a67a', + '--text-header': '#d9e6d9', + '--text-bright': '#d9e6d9', + '--text-dim': '#a3b3a3', + '--text-muted': '#7a8a7a', + '--surface-dark': '#243224', + '--surface-hover': '#2e3a2e', + '--surface-overlay': '#1b2a1b', + '--console-info': '#7a9a7a', + '--console-warning': '#c9a67a', + '--console-error': '#ff6b6b', + '--console-success': '#7a9a7a', + }, + 'Ramsö Sjöwind': { + '--primary': '#68c1e8', + '--bg-dark': '#1a2a38', + '--bg-panel': '#253545', + '--accent': '#68c1e8', + '--danger': '#ff6b6b', + '--success': '#68c1e8', + '--warning': '#f0ad4e', + '--text-header': '#e0eaf0', + '--text-bright': '#e0eaf0', + '--text-dim': '#b0c0d0', + '--text-muted': '#8aa0b0', + '--surface-dark': '#2f4055', + '--surface-hover': '#3a4c66', + '--surface-overlay': '#253545', + '--console-info': '#68c1e8', + '--console-warning': '#f0ad4e', + '--console-error': '#ff6b6b', + '--console-success': '#68c1e8', + }, + 'Rindö Solnedgang': { + '--primary': '#ff9e7a', + '--bg-dark': '#272133', + '--bg-panel': '#332940', + '--accent': '#ff9e7a', + '--danger': '#ff6b6b', + '--success': '#66d020', + '--warning': '#ffcc66', + '--text-header': '#f5e6ff', + '--text-bright': '#f5e6ff', + '--text-dim': '#d1b6e1', + '--text-muted': '#b89ac7', + '--surface-dark': '#3e304d', + '--surface-hover': '#4b3a5d', + '--surface-overlay': '#332940', + '--console-info': '#ff9e7a', + '--console-warning': '#ffcc66', + '--console-error': '#ff6b6b', + '--console-success': '#66d020', + }, + 'Mint Choklad': { + '--primary': '#7fe0c3', + '--bg-dark': '#1e2721', + '--bg-panel': '#26322a', + '--accent': '#7fe0c3', + '--danger': '#ff6b6b', + '--success': '#7fe0c3', + '--warning': '#d9b382', + '--text-header': '#e0f0e8', + '--text-bright': '#e0f0e8', + '--text-dim': '#b0c5b8', + '--text-muted': '#8fa9a3', + '--surface-dark': '#2e3d33', + '--surface-hover': '#38493e', + '--surface-overlay': '#26322a', + '--console-info': '#7fe0c3', + '--console-warning': '#d9b382', + '--console-error': '#ff6b6b', + '--console-success': '#7fe0c3', + }, + 'Lavendel Fält': { + '--primary': '#b28dff', + '--bg-dark': '#2b2440', + '--bg-panel': '#352e4e', + '--accent': '#b28dff', + '--danger': '#ff6b6b', + '--success': '#66d020', + '--warning': '#ffad9c', + '--text-header': '#ece8ff', + '--text-bright': '#ece8ff', + '--text-dim': '#c7c0e3', + '--text-muted': '#a99cc9', + '--surface-dark': '#3f385c', + '--surface-hover': '#4a426a', + '--surface-overlay': '#352e4e', + '--console-info': '#b28dff', + '--console-warning': '#ffad9c', + '--console-error': '#ff6b6b', + '--console-success': '#66d020', + }, + 'Midsommar': { + '--primary': '#ffd700', + '--bg-dark': '#1a1a2e', + '--bg-panel': '#232342', + '--accent': '#ffd700', + '--danger': '#ff6b6b', + '--success': '#66d020', + '--warning': '#ff6b9d', + '--text-header': '#fff4d6', + '--text-bright': '#fff4d6', + '--text-dim': '#e6d5a8', + '--text-muted': '#ccc088', + '--surface-dark': '#2d2d56', + '--surface-hover': '#3a3a6a', + '--surface-overlay': '#232342', + '--console-info': '#ffd700', + '--console-warning': '#ff6b9d', + '--console-error': '#ff6b6b', + '--console-success': '#66d020', + }, + 'Kireness': { + '--primary': '#80DEEA', + '--bg-dark': '#0A1215', + '--bg-panel': '#1225308f', + '--accent': '#4FC3F7', + '--danger': '#EF5350', + '--success': '#66BB6A', + '--warning': '#FFA726', + '--text-header': '#ECEFF1', + '--text-bright': '#B0BEC5', + '--text-dim': '#78909C', + '--text-muted': '#546E7A', + '--surface-dark': '#1A2D35', + '--surface-hover': '#253D48', + '--surface-overlay': '#152228', + '--console-info': '#4FC3F7', + '--console-warning': '#FFA726', + '--console-error': '#EF5350', + '--console-success': '#66BB6A', + }, + 'Kiruna': { + '--primary': '#3ddbd9', + '--bg-dark': '#0d1b2a', + '--bg-panel': '#1b263b', + '--accent': '#3ddbd9', + '--danger': '#ee6c4d', + '--success': '#3ddbd9', + '--warning': '#ee6c4d', + '--text-header': '#e0fbfc', + '--text-bright': '#e0fbfc', + '--text-dim': '#98c1d9', + '--text-muted': '#6a9ab8', + '--surface-dark': '#253347', + '--surface-hover': '#2f3e53', + '--surface-overlay': '#1b263b', + '--console-info': '#3ddbd9', + '--console-warning': '#ee6c4d', + '--console-error': '#ee6c4d', + '--console-success': '#3ddbd9', + }, + 'Lingon': { + '--primary': '#ff3864', + '--bg-dark': '#2d1b1e', + '--bg-panel': '#3d252a', + '--accent': '#ff3864', + '--danger': '#ff3864', + '--success': '#7fe0c3', + '--warning': '#ffa07a', + '--text-header': '#ffe8ed', + '--text-bright': '#ffe8ed', + '--text-dim': '#deb8c4', + '--text-muted': '#c49aaa', + '--surface-dark': '#4d2f36', + '--surface-hover': '#5d3942', + '--surface-overlay': '#3d252a', + '--console-info': '#ff3864', + '--console-warning': '#ffa07a', + '--console-error': '#ff3864', + '--console-success': '#7fe0c3', + }, + 'Saffran': { + '--primary': '#f4a261', + '--bg-dark': '#2a1f15', + '--bg-panel': '#3a2a1e', + '--accent': '#f4a261', + '--danger': '#e76f51', + '--success': '#66d020', + '--warning': '#e76f51', + '--text-header': '#fff5e6', + '--text-bright': '#fff5e6', + '--text-dim': '#e6d4b8', + '--text-muted': '#ccb8a0', + '--surface-dark': '#4a3527', + '--surface-hover': '#5a4030', + '--surface-overlay': '#3a2a1e', + '--console-info': '#f4a261', + '--console-warning': '#e76f51', + '--console-error': '#e76f51', + '--console-success': '#66d020', + }, + 'Göteborg': { + '--primary': '#ff10f0', + '--bg-dark': '#0f0320', + '--bg-panel': '#1a0835', + '--accent': '#ff10f0', + '--danger': '#ffff00', + '--success': '#39ff14', + '--warning': '#ffff00', + '--text-header': '#f0e6ff', + '--text-bright': '#f0e6ff', + '--text-dim': '#c8b6e2', + '--text-muted': '#a899c7', + '--surface-dark': '#250d4a', + '--surface-hover': '#30125f', + '--surface-overlay': '#1a0835', + '--console-info': '#00f0ff', + '--console-warning': '#ffff00', + '--console-error': '#ff10f0', + '--console-success': '#39ff14', + }, + 'Blåbär': { + '--primary': '#6b88ff', + '--bg-dark': '#1a1f3a', + '--bg-panel': '#242c4a', + '--accent': '#6b88ff', + '--danger': '#ff6b6b', + '--success': '#66d020', + '--warning': '#c77dff', + '--text-header': '#e8eeff', + '--text-bright': '#e8eeff', + '--text-dim': '#b8c8e8', + '--text-muted': '#9ab0d8', + '--surface-dark': '#2e395a', + '--surface-hover': '#38466a', + '--surface-overlay': '#242c4a', + '--console-info': '#6b88ff', + '--console-warning': '#c77dff', + '--console-error': '#ff6b6b', + '--console-success': '#66d020', + }, + 'Rabarber': { + '--primary': '#ff6b9d', + '--bg-dark': '#1f1a1d', + '--bg-panel': '#2d242a', + '--accent': '#ff6b9d', + '--danger': '#ff6b9d', + '--success': '#7fe0c3', + '--warning': '#ffa07a', + '--text-header': '#ffe8f5', + '--text-bright': '#ffe8f5', + '--text-dim': '#e6b8d8', + '--text-muted': '#cc9acc', + '--surface-dark': '#3b2e37', + '--surface-hover': '#493844', + '--surface-overlay': '#2d242a', + '--console-info': '#ff6b9d', + '--console-warning': '#ffa07a', + '--console-error': '#ff6b9d', + '--console-success': '#7fe0c3', + }, + }; + + /*Get the current saved theme from localStorage, or null if none.*/ + function getSavedTheme() { + try { + const raw = localStorage.getItem(STORAGE_KEY); + return raw ? JSON.parse(raw) : null; + } catch { + return null; + } + } + + /*Save a theme object to localStorage.*/ + function saveTheme(themeObj) { + localStorage.setItem(STORAGE_KEY, JSON.stringify(themeObj)); + } + + /* Remove the saved theme (revert to CSS defaults).*/ + function clearTheme() { + localStorage.removeItem(STORAGE_KEY); + // Remove all overrides from :root + const root = document.documentElement; + THEME_VARS.forEach(v => root.style.removeProperty(v.variable)); + } + + /* Apply a theme object to the document (sets CSS custom properties on :root).*/ + function applyTheme(themeObj) { + if (!themeObj) return; + const root = document.documentElement; + Object.entries(themeObj).forEach(([varName, value]) => { + if (value) root.style.setProperty(varName, value); + }); + } + + /* Read the current computed values of all theme variables.*/ + function getCurrentTheme() { + const computed = getComputedStyle(document.documentElement); + const theme = {}; + THEME_VARS.forEach(v => { + // Try inline override first, then computed + const inline = document.documentElement.style.getPropertyValue(v.variable).trim(); + const comp = computed.getPropertyValue(v.variable).trim(); + theme[v.variable] = inline || comp; + }); + return theme; + } + + /* Load and apply saved theme on page load.*/ + function init() { + const saved = getSavedTheme(); + if (saved) applyTheme(saved); + } + + /* Export the current theme as a JSON string (for sharing).*/ + + function exportTheme() { + const saved = getSavedTheme(); + return JSON.stringify(saved || getCurrentTheme(), null, 2); + } + + /* Import a theme from a JSON string.*/ + function importTheme(jsonStr) { + try { + const theme = JSON.parse(jsonStr); + if (typeof theme !== 'object' || theme === null) throw new Error('Invalid theme'); + applyTheme(theme); + saveTheme(theme); + return true; + } catch (e) { + console.error('Theme import failed:', e); + return false; + } + } + + // Auto-init on load + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } + + return { + THEME_VARS, + PRESETS, + getSavedTheme, + saveTheme, + clearTheme, + applyTheme, + getCurrentTheme, + exportTheme, + importTheme, + init, + }; +})(); diff --git a/UIMod/onboard_bundled/ui/config.html b/UIMod/onboard_bundled/ui/config.html index 95b3a538..329daeb3 100644 --- a/UIMod/onboard_bundled/ui/config.html +++ b/UIMod/onboard_bundled/ui/config.html @@ -13,6 +13,7 @@ + @@ -60,6 +61,10 @@

{{.UIText_ConfigHeadline}}

{{.UIText_DetectionManager}} + @@ -588,7 +593,7 @@

Beta Feature

{{.UIText_SLP_Title}}

{{.UIText_SLP_Description}}

-

{{.UIText_SLP_ReadyToInstall}}

+

{{.UIText_SLP_ReadyToInstall}}

@@ -622,7 +627,7 @@

{{.UIText_SLP_UploadModPackage}}

{{.UIText_SLP_ManageInstallation}}

-

⚠️ {{.UIText_SLP_UninstallWarning}}

+

⚠️ {{.UIText_SLP_UninstallWarning}}

@@ -729,6 +734,10 @@

Regex Detection:

+
+
+
+ + diff --git a/src/discordbot/logstream.go b/src/discordbot/logstream.go index 9212d9a5..f70ab3c8 100644 --- a/src/discordbot/logstream.go +++ b/src/discordbot/logstream.go @@ -34,9 +34,11 @@ func flushLogBufferToDiscord() { for len(message) > 0 { // Determine how much of the message we can send - chunkSize := discordMaxMessageLength - if len(message) < discordMaxMessageLength { - chunkSize = len(message) + chunkSize := min(len(message), discordMaxMessageLength) + + // if the message is empty len 0, break to avoid infinite loop + if chunkSize == 0 { + break } // Send the chunk to Discord