mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-23 18:20:52 +00:00
## Description: We have brand colors: <img width="738" height="900" alt="Screenshot 2026-04-25 at 12 52 29 PM" src="https://github.com/user-attachments/assets/aac69e87-91f2-4c3f-9f1e-f69f48f5943e" /> So update the homepage & in-game UI to use those colors: <img width="1185" height="946" alt="Screenshot 2026-04-25 at 12 51 06 PM" src="https://github.com/user-attachments/assets/89a0b12c-2db1-43d4-9500-fcf405c0f7ff" /> Also updated buttons to use the o-button element ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: evan
150 lines
6.5 KiB
TypeScript
150 lines
6.5 KiB
TypeScript
import { LitElement, html } from "lit";
|
|
import { customElement, property, query, state } from "lit/decorators.js";
|
|
import { translateText } from "../Utils";
|
|
|
|
@customElement("fluent-slider")
|
|
export class FluentSlider extends LitElement {
|
|
createRenderRoot() {
|
|
return this;
|
|
}
|
|
|
|
@property({ type: Number }) value = 0;
|
|
@property({ type: Number }) min = 0;
|
|
@property({ type: Number }) max = 400;
|
|
@property({ type: Number }) step = 1;
|
|
@property({ type: String }) labelKey = "";
|
|
@property({ type: String }) disabledKey = "";
|
|
@property({ type: Number }) defaultValue: number | undefined = undefined;
|
|
@property({ type: String }) defaultLabelKey = "";
|
|
|
|
@state() private isEditing = false;
|
|
|
|
@query("input[type='number']") private numberInput!: HTMLInputElement;
|
|
|
|
private dispatchValueChange() {
|
|
this.dispatchEvent(
|
|
new CustomEvent("value-changed", {
|
|
detail: { value: this.value },
|
|
bubbles: true,
|
|
composed: true,
|
|
}),
|
|
);
|
|
}
|
|
|
|
private handleSliderInput(e: Event) {
|
|
const target = e.target as HTMLInputElement;
|
|
this.value = target.valueAsNumber;
|
|
}
|
|
|
|
private handleSliderChange(e: Event) {
|
|
const target = e.target as HTMLInputElement;
|
|
this.value = target.valueAsNumber;
|
|
this.dispatchValueChange();
|
|
}
|
|
|
|
private handleNumberInput(e: Event) {
|
|
const target = e.target as HTMLInputElement;
|
|
let val = target.valueAsNumber;
|
|
if (isNaN(val)) {
|
|
val = this.min;
|
|
}
|
|
if (val < this.min) val = this.min;
|
|
if (val > this.max) val = this.max;
|
|
this.value = val;
|
|
// Don't dispatch value change on every input - only on blur/enter
|
|
}
|
|
|
|
private handleNumberComplete() {
|
|
// Dispatch the value change when editing is complete
|
|
this.dispatchValueChange();
|
|
}
|
|
|
|
private handleNumberKeyDown(e: KeyboardEvent) {
|
|
if (e.key === "Enter") {
|
|
this.isEditing = false;
|
|
this.handleNumberComplete();
|
|
}
|
|
}
|
|
|
|
private enableEditing() {
|
|
this.isEditing = true;
|
|
this.updateComplete.then(() => this.numberInput?.focus());
|
|
}
|
|
|
|
render() {
|
|
const percentage =
|
|
this.max === this.min
|
|
? 0
|
|
: ((this.value - this.min) / (this.max - this.min)) * 100;
|
|
return html`
|
|
<div
|
|
class="flex flex-col items-center justify-center gap-1 w-full text-center"
|
|
>
|
|
<input
|
|
type="range"
|
|
.min=${this.min}
|
|
.max=${this.max}
|
|
.step=${this.step}
|
|
.valueAsNumber=${this.value}
|
|
style="background: linear-gradient(to right, var(--color-malibu-blue) 0%, var(--color-malibu-blue) ${percentage}%, rgba(255, 255, 255, 0.15) ${percentage}%, rgba(255, 255, 255, 0.15) 100%); background-size: 100% 6px; background-repeat: no-repeat; background-position: center; border-radius: 9999px;"
|
|
class="w-full h-6 p-0 m-0 bg-transparent appearance-none cursor-pointer focus:outline-none
|
|
[&::-webkit-slider-runnable-track]:w-full [&::-webkit-slider-runnable-track]:h-[6px] [&::-webkit-slider-runnable-track]:cursor-pointer [&::-webkit-slider-runnable-track]:bg-transparent [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:transition-colors
|
|
[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:h-[18px] [&::-webkit-slider-thumb]:w-[18px] [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-malibu-blue [&::-webkit-slider-thumb]:cursor-pointer [&::-webkit-slider-thumb]:-mt-[6px] [&::-webkit-slider-thumb]:shadow-[var(--shadow-malibu-blue-ring-sm)] [&::-webkit-slider-thumb]:transition-all active:[&::-webkit-slider-thumb]:scale-110 active:[&::-webkit-slider-thumb]:shadow-[var(--shadow-malibu-blue-ring-lg)]
|
|
[&::-moz-range-track]:w-full [&::-moz-range-track]:h-[6px] [&::-moz-range-track]:cursor-pointer [&::-moz-range-track]:bg-transparent [&::-moz-range-track]:rounded-full [&::-moz-range-track]:transition-colors
|
|
[&::-moz-range-thumb]:h-[18px] [&::-moz-range-thumb]:w-[18px] [&::-moz-range-thumb]:border-none [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-malibu-blue [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-thumb]:shadow-[var(--shadow-malibu-blue-ring-sm)] [&::-moz-range-thumb]:transition-all active:[&::-moz-range-thumb]:scale-110 active:[&::-moz-range-thumb]:shadow-[var(--shadow-malibu-blue-ring-lg)]"
|
|
@input=${this.handleSliderInput}
|
|
@change=${this.handleSliderChange}
|
|
/>
|
|
<div
|
|
class="text-xs uppercase font-bold tracking-wider text-center w-full leading-tight mb-1 flex flex-col items-center ${this
|
|
.value > 0
|
|
? "text-white"
|
|
: "text-white/60"}"
|
|
>
|
|
<span>${this.labelKey ? translateText(this.labelKey) : ""}</span>
|
|
${this.isEditing
|
|
? html`<input
|
|
type="number"
|
|
.min=${this.min}
|
|
.max=${this.max}
|
|
.valueAsNumber=${this.value}
|
|
class="w-[60px] bg-black/60 text-white border border-white/20 text-center rounded text-sm p-1 leading-none font-bold font-inherit mt-1 focus:outline-none focus:border-blue-500"
|
|
@input=${this.handleNumberInput}
|
|
@blur=${() => {
|
|
this.isEditing = false;
|
|
this.handleNumberComplete();
|
|
}}
|
|
@keydown=${this.handleNumberKeyDown}
|
|
/>`
|
|
: html`<span
|
|
class="cursor-pointer min-w-[60px] inline-block text-center text-sm font-bold select-none hover:text-white transition-colors mt-1 ${this
|
|
.value > 0
|
|
? "text-white"
|
|
: "text-white/60"}"
|
|
role="button"
|
|
tabindex="0"
|
|
@click=${this.enableEditing}
|
|
@keydown=${(e: KeyboardEvent) => {
|
|
if (e.key === "Enter" || e.key === " ") {
|
|
this.enableEditing();
|
|
e.preventDefault();
|
|
}
|
|
}}
|
|
>
|
|
${this.value === 0 && this.disabledKey
|
|
? translateText(this.disabledKey)
|
|
: this.defaultValue !== undefined &&
|
|
this.value === this.defaultValue &&
|
|
this.defaultLabelKey
|
|
? html`${this.value}
|
|
<span class="text-white/40 uppercase"
|
|
>(${translateText(this.defaultLabelKey)})</span
|
|
>`
|
|
: this.value}
|
|
</span>`}
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|