feat: implement modern glassmorphism design system with multi-theme support and primary generator components
This commit is contained in:
1 parent
aeeb37770b
commit
35f1ce9783
3 files changed
+96
-96
No files matched your search
@@ -2114,14 +2114,6 @@ html[data-theme^="dark"] .m3-segment-item:hover:not(.active):not(.disabled) {
|
||||
border-radius: var(--md-shape-corner-full);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 550;
|
||||
cursor: pointer;
|
||||
transition: all var(--md-transition-duration);
|
||||
}
|
||||
|
||||
.status-chip:hover {
|
||||
background-color: var(--md-sys-color-primary-container);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.prompt-actions {
|
||||
|
||||
@@ -683,28 +683,7 @@ function Generator({
|
||||
<div className="m3-field-group">
|
||||
{/* Prompt Textarea */}
|
||||
<div className="m3-text-field">
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||
<label className="m3-text-field-label">Positive Prompt</label>
|
||||
<button
|
||||
type="button"
|
||||
className="m3-btn m3-btn-tonal"
|
||||
style={{ height: "28px", padding: "0 10px", fontSize: "0.75rem", borderRadius: "14px", display: "flex", alignItems: "center", gap: "4px" }}
|
||||
onClick={handleEnhancePrompt}
|
||||
disabled={isGenerating || isEnhancing || !prompt.trim()}
|
||||
>
|
||||
{isEnhancing ? (
|
||||
<>
|
||||
<span className="progress-spinner" style={{ width: "12px", height: "12px", borderWidth: "2px" }} />
|
||||
<span>Enhancing...</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Sparkles size={12} />
|
||||
<span>Enhance Prompt</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<label className="m3-text-field-label">Image Prompt</label>
|
||||
<textarea
|
||||
className="m3-textarea"
|
||||
value={prompt}
|
||||
@@ -714,19 +693,6 @@ function Generator({
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Negative Prompt Text Input */}
|
||||
<div className="m3-text-field">
|
||||
<label className="m3-text-field-label">Negative Prompt (Optional)</label>
|
||||
<input
|
||||
type="text"
|
||||
className="m3-input"
|
||||
value={negativePrompt}
|
||||
onChange={(e) => setNegativePrompt(e.target.value)}
|
||||
placeholder="Items to avoid (e.g. 'blurry, low quality, deformed hands, texts')..."
|
||||
disabled={isGenerating}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{constraints.backendType !== "apple-npu" && constraints.backendType !== "openvino-npu" && (
|
||||
<div className="m3-text-field">
|
||||
<label className="m3-text-field-label">Base Image (Optional)</label>
|
||||
@@ -789,19 +755,19 @@ function Generator({
|
||||
<div className="m3-text-field">
|
||||
<label className="m3-text-field-label">Active Image Constraints</label>
|
||||
<div className="chips-container">
|
||||
<div className="status-chip" onClick={() => setActiveTab("constraints")}>
|
||||
<div className="status-chip">
|
||||
<Sliders size={14} />
|
||||
<span>Resolution: {constraints.width}x{constraints.height}</span>
|
||||
</div>
|
||||
<div className="status-chip" onClick={() => setActiveTab("constraints")}>
|
||||
<div className="status-chip">
|
||||
<RefreshCw size={14} />
|
||||
<span>Steps: {constraints.steps}</span>
|
||||
</div>
|
||||
<div className="status-chip" onClick={() => setActiveTab("constraints")}>
|
||||
<div className="status-chip">
|
||||
<Sparkles size={14} />
|
||||
<span>Sampler: {constraints.sampler}</span>
|
||||
</div>
|
||||
<div className="status-chip" onClick={() => setActiveTab("constraints")}>
|
||||
<div className="status-chip">
|
||||
<span>Seed: {constraints.seed === -1 ? "Random" : constraints.seed}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -423,10 +423,48 @@ function Settings({
|
||||
};
|
||||
|
||||
const updateTextSetting = (key, value) => {
|
||||
setPendingTextSettings((prev) => ({
|
||||
...prev,
|
||||
[key]: value
|
||||
}));
|
||||
setPendingTextSettings((prev) => {
|
||||
const updated = { ...prev, [key]: value };
|
||||
|
||||
// If the user selected a preset performance profile, apply its hardware parameters
|
||||
if (key === "performanceProfile") {
|
||||
const presets = specs?.recommended_text_settings;
|
||||
if (presets) {
|
||||
let preset = null;
|
||||
if (value === "potato") preset = presets.low;
|
||||
else if (value === "balanced") preset = presets.mid;
|
||||
else if (value === "high") preset = presets.high;
|
||||
|
||||
if (preset) {
|
||||
Object.assign(updated, {
|
||||
contextSize: preset.contextSize,
|
||||
threads: preset.threads,
|
||||
gpuLayers: preset.gpuLayers,
|
||||
cacheTypeK: preset.cacheTypeK,
|
||||
cacheTypeV: preset.cacheTypeV,
|
||||
flashAttn: preset.flashAttn,
|
||||
mlock: preset.mlock,
|
||||
mmap: preset.mmap,
|
||||
cachePrompt: preset.cachePrompt,
|
||||
batchSize: preset.batchSize,
|
||||
ubatchSize: preset.ubatchSize,
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If the user manually overrides any performance-related setting, auto-switch profile to "custom"
|
||||
const isPerformanceKey = [
|
||||
"contextSize", "threads", "gpuLayers", "cacheTypeK", "cacheTypeV",
|
||||
"flashAttn", "mlock", "mmap", "cachePrompt", "batchSize", "ubatchSize"
|
||||
].includes(key);
|
||||
|
||||
if (isPerformanceKey) {
|
||||
updated.performanceProfile = "custom";
|
||||
}
|
||||
}
|
||||
|
||||
return updated;
|
||||
});
|
||||
};
|
||||
|
||||
const updateSpeechSetting = (key, value) => {
|
||||
@@ -1093,6 +1131,8 @@ function Settings({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{llmBackends.available?.length > 1 && (
|
||||
<div className="m3-slider-group">
|
||||
<div className="m3-slider-header">
|
||||
@@ -1186,57 +1226,59 @@ function Settings({
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{hasPendingChanges && (
|
||||
<div className="settings-save-bar" style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
padding: "16px 20px",
|
||||
background: "color-mix(in srgb, var(--md-sys-color-primary) 10%, var(--bg-card))",
|
||||
border: "1px solid color-mix(in srgb, var(--md-sys-color-primary) 30%, transparent)",
|
||||
borderRadius: "14px",
|
||||
marginTop: "20px",
|
||||
gap: "16px",
|
||||
flexWrap: "wrap",
|
||||
animation: "fadeIn 0.2s ease",
|
||||
width: "100%",
|
||||
boxSizing: "border-box"
|
||||
}}>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "10px" }}>
|
||||
<Brain size={18} style={{ color: "var(--md-sys-color-primary)" }} />
|
||||
<div>
|
||||
<div style={{ fontWeight: 600, fontSize: "0.9rem" }}>Unsaved Text Generation Settings</div>
|
||||
<div style={{ fontSize: "0.85rem", opacity: 0.8, marginTop: "2px" }}>
|
||||
{llmStatus.ready
|
||||
? "Saving will unload the active text model to apply changes."
|
||||
: "Changes will be applied on the next model load."}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="m3-btn m3-btn-filled"
|
||||
onClick={handleSaveTextSettings}
|
||||
style={{
|
||||
background: "var(--md-sys-color-primary)",
|
||||
color: "var(--md-sys-color-on-primary)",
|
||||
border: "none",
|
||||
borderRadius: "10px",
|
||||
padding: "10px 18px",
|
||||
fontWeight: 600,
|
||||
fontSize: "0.85rem",
|
||||
cursor: "pointer",
|
||||
boxShadow: "0 2px 8px color-mix(in srgb, var(--md-sys-color-primary) 30%, transparent)",
|
||||
}}
|
||||
>
|
||||
Save & Apply Changes
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{hasPendingChanges && (
|
||||
<div className="settings-save-bar" style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
padding: "16px 20px",
|
||||
background: "color-mix(in srgb, var(--md-sys-color-primary) 10%, var(--bg-card))",
|
||||
border: "1px solid color-mix(in srgb, var(--md-sys-color-primary) 30%, transparent)",
|
||||
borderRadius: "14px",
|
||||
marginTop: "20px",
|
||||
gap: "16px",
|
||||
flexWrap: "wrap",
|
||||
animation: "fadeIn 0.2s ease",
|
||||
}}>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "10px" }}>
|
||||
<Brain size={18} style={{ color: "var(--md-sys-color-primary)" }} />
|
||||
<div>
|
||||
<div style={{ fontWeight: 600, fontSize: "0.9rem" }}>Unsaved Text Generation Settings</div>
|
||||
<div style={{ fontSize: "0.85rem", opacity: 0.8, marginTop: "2px" }}>
|
||||
{llmStatus.ready
|
||||
? "Saving will unload the active text model to apply changes."
|
||||
: "Changes will be applied on the next model load."}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="m3-btn m3-btn-filled"
|
||||
onClick={handleSaveTextSettings}
|
||||
style={{
|
||||
background: "var(--md-sys-color-primary)",
|
||||
color: "var(--md-sys-color-on-primary)",
|
||||
border: "none",
|
||||
borderRadius: "10px",
|
||||
padding: "10px 18px",
|
||||
fontWeight: 600,
|
||||
fontSize: "0.85rem",
|
||||
cursor: "pointer",
|
||||
boxShadow: "0 2px 8px color-mix(in srgb, var(--md-sys-color-primary) 30%, transparent)",
|
||||
}}
|
||||
>
|
||||
Save & Apply Changes
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
Reference in new issue
Block a user