Add dark theme, richer Markdown and readable plugin results. Improve Android input evidence, response integrity and diagnostics. Unify lifecycle, guidance receipts and evidence sources across clients. Keep direct action dispatch without an added AI quota approval layer. Align version metadata at 2.2.0 and bundle Helper 1.2.2. Validation: 3063 backend tests before the version bump; 44 after. Frontend: 317 tests and production build passed.
47 lines
3.2 KiB
TypeScript
47 lines
3.2 KiB
TypeScript
import { Component, computed, input, output } from '@angular/core';
|
|
|
|
@Component({
|
|
selector: 'app-setting-slider', standalone: true,
|
|
template: `
|
|
<div class="slider-heading"><span>{{label()}}</span><output>{{display()}}</output></div>
|
|
<input type="range" min="0" [max]="values().length - 1" step="1" [value]="index()"
|
|
[disabled]="disabled()" [attr.aria-label]="label()" [attr.aria-valuetext]="display()"
|
|
[style.--fill]="(index() / (values().length - 1) * 100) + '%'"
|
|
(input)="change($any($event.target).value)" />
|
|
<div class="slider-ends"><span>{{labels()[0] || values()[0]}}</span><span>{{labels().at(-1) || values().at(-1)}}</span></div>
|
|
@if(hint()){<p>{{hint()}}</p>}
|
|
`,
|
|
styles: [`
|
|
:host{display:block;min-width:0;padding:14px 16px;background:var(--app-surface-soft, #f8fafc);border:1px solid var(--app-border, #e2e8f0);border-radius:14px;font-size:13px;color:var(--app-text-control, #334155)}
|
|
.slider-heading,.slider-ends{display:flex;align-items:center;justify-content:space-between;gap:10px}
|
|
.slider-heading{font-weight:600}output{color:var(--app-exploration-text, #4f46e5);font-size:12px;white-space:nowrap}.slider-ends{font-size:11px;color:var(--app-text-muted, #64748b)}
|
|
input{appearance:none;display:block;box-sizing:border-box;width:100%;height:6px;border:0;border-radius:10px;margin:20px 0 12px;background:linear-gradient(to right,#6366f1 var(--fill),var(--app-primary-soft, #dbe3ee) var(--fill));cursor:pointer}
|
|
input::-webkit-slider-thumb{appearance:none;width:18px;height:18px;border-radius:50%;background:var(--app-surface, #fff);border:2px solid #6366f1;box-shadow:0 2px 6px #33415526}
|
|
input::-moz-range-thumb{width:14px;height:14px;border-radius:50%;background:var(--app-surface, #fff);border:2px solid #6366f1}
|
|
input:focus-visible{outline:2px solid var(--app-primary-border, #a5b4fc);outline-offset:5px}input:disabled{opacity:.5;cursor:default}p{margin:10px 0 0;font-size:12px;line-height:1.6;color:var(--app-text-muted, #64748b)}
|
|
`]
|
|
})
|
|
export class SettingSliderComponent {
|
|
label = input.required<string>();
|
|
value = input.required<string | number>();
|
|
values = input.required<(string | number)[]>();
|
|
labels = input<string[]>([]);
|
|
hint = input('');
|
|
disabled = input(false);
|
|
valueChange = output<any>();
|
|
index = computed(() => {
|
|
const exact = this.values().indexOf(this.value());
|
|
if(exact >= 0) return exact;
|
|
if(typeof this.value() === 'number') return this.values().reduce<number>((best, v, i) => Math.abs(Number(v)-Number(this.value())) < Math.abs(Number(this.values()[best])-Number(this.value())) ? i : best, 0);
|
|
return 0;
|
|
});
|
|
display = computed(() => {
|
|
const exact = this.values().indexOf(this.value());
|
|
return exact >= 0 ? this.labels()[exact] || String(this.value()) : String(this.value()) + (typeof this.value() === 'number' ? ' 秒' : '');
|
|
});
|
|
change(index: string) { this.valueChange.emit(this.values()[Number(index)]); }
|
|
}
|
|
|
|
export const REASONING_VALUES = ['default','none','minimal','low','medium','high','xhigh','max'];
|
|
export const REASONING_LABELS = ['模型默认','关闭 · none','最低 · minimal','低 · low','中 · medium','高 · high','极高 · xhigh','最高 · max'];
|