mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 21:42:51 -05:00
Compare commits
5 Commits
1194f3ffb8
...
9fc0d5efff
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fc0d5efff | ||
|
|
6611dfbe05 | ||
|
|
8a71ead51d | ||
|
|
d9d6ab5776 | ||
|
|
d6fe7bea27 |
@@ -42,16 +42,7 @@ func HandleList(conn net.Conn, req models.Request) {
|
||||
Installed: installed,
|
||||
FirstParty: isFirstParty(t.Author),
|
||||
}
|
||||
if t.Variants != nil && len(t.Variants.Options) > 0 {
|
||||
info.HasVariants = true
|
||||
info.Variants = &VariantsInfo{
|
||||
Default: t.Variants.Default,
|
||||
Options: make([]VariantInfo, len(t.Variants.Options)),
|
||||
}
|
||||
for j, v := range t.Variants.Options {
|
||||
info.Variants.Options[j] = VariantInfo{ID: v.ID, Name: v.Name}
|
||||
}
|
||||
}
|
||||
addVariantsInfo(&info, t.Variants)
|
||||
result[i] = info
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,64 @@ import (
|
||||
)
|
||||
|
||||
func addVariantsInfo(info *ThemeInfo, variants *themes.ThemeVariants) {
|
||||
if variants == nil || len(variants.Options) == 0 {
|
||||
if variants == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if variants.Type == "multi" {
|
||||
if len(variants.Flavors) == 0 && len(variants.Accents) == 0 {
|
||||
return
|
||||
}
|
||||
info.HasVariants = true
|
||||
info.Variants = &VariantsInfo{
|
||||
Type: "multi",
|
||||
Flavors: make([]FlavorInfo, len(variants.Flavors)),
|
||||
Accents: make([]AccentInfo, len(variants.Accents)),
|
||||
}
|
||||
if variants.Defaults != nil {
|
||||
info.Variants.Defaults = &MultiDefaults{
|
||||
Dark: variants.Defaults.Dark,
|
||||
Light: variants.Defaults.Light,
|
||||
}
|
||||
}
|
||||
for i, f := range variants.Flavors {
|
||||
mode := ""
|
||||
switch {
|
||||
case f.Dark.Primary != "" && f.Light.Primary != "":
|
||||
mode = "both"
|
||||
case f.Dark.Primary != "":
|
||||
mode = "dark"
|
||||
case f.Light.Primary != "":
|
||||
mode = "light"
|
||||
default:
|
||||
if f.Dark.Surface != "" {
|
||||
mode = "dark"
|
||||
} else if f.Light.Surface != "" {
|
||||
mode = "light"
|
||||
}
|
||||
}
|
||||
info.Variants.Flavors[i] = FlavorInfo{ID: f.ID, Name: f.Name, Mode: mode}
|
||||
}
|
||||
for i, a := range variants.Accents {
|
||||
color := ""
|
||||
if colors, ok := a.FlavorColors["mocha"]; ok && colors.Primary != "" {
|
||||
color = colors.Primary
|
||||
} else if colors, ok := a.FlavorColors["latte"]; ok && colors.Primary != "" {
|
||||
color = colors.Primary
|
||||
} else {
|
||||
for _, c := range a.FlavorColors {
|
||||
if c.Primary != "" {
|
||||
color = c.Primary
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
info.Variants.Accents[i] = AccentInfo{ID: a.ID, Name: a.Name, Color: color}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if len(variants.Options) == 0 {
|
||||
return
|
||||
}
|
||||
info.HasVariants = true
|
||||
|
||||
@@ -5,9 +5,30 @@ type VariantInfo struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type FlavorInfo struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Mode string `json:"mode,omitempty"`
|
||||
}
|
||||
|
||||
type AccentInfo struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Color string `json:"color,omitempty"`
|
||||
}
|
||||
|
||||
type MultiDefaults struct {
|
||||
Dark map[string]string `json:"dark,omitempty"`
|
||||
Light map[string]string `json:"light,omitempty"`
|
||||
}
|
||||
|
||||
type VariantsInfo struct {
|
||||
Default string `json:"default,omitempty"`
|
||||
Options []VariantInfo `json:"options,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Default string `json:"default,omitempty"`
|
||||
Defaults *MultiDefaults `json:"defaults,omitempty"`
|
||||
Options []VariantInfo `json:"options,omitempty"`
|
||||
Flavors []FlavorInfo `json:"flavors,omitempty"`
|
||||
Accents []AccentInfo `json:"accents,omitempty"`
|
||||
}
|
||||
|
||||
type ThemeInfo struct {
|
||||
|
||||
@@ -2,6 +2,7 @@ package themes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -40,9 +41,67 @@ type ThemeVariant struct {
|
||||
Light ColorScheme `json:"light,omitempty"`
|
||||
}
|
||||
|
||||
type ThemeFlavor struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Dark ColorScheme `json:"dark,omitempty"`
|
||||
Light ColorScheme `json:"light,omitempty"`
|
||||
}
|
||||
|
||||
type ThemeAccent struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
FlavorColors map[string]ColorScheme `json:"-"`
|
||||
}
|
||||
|
||||
func (a *ThemeAccent) UnmarshalJSON(data []byte) error {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return err
|
||||
}
|
||||
a.FlavorColors = make(map[string]ColorScheme)
|
||||
var mErr error
|
||||
for key, value := range raw {
|
||||
switch key {
|
||||
case "id":
|
||||
mErr = errors.Join(mErr, json.Unmarshal(value, &a.ID))
|
||||
case "name":
|
||||
mErr = errors.Join(mErr, json.Unmarshal(value, &a.Name))
|
||||
default:
|
||||
var colors ColorScheme
|
||||
if err := json.Unmarshal(value, &colors); err == nil {
|
||||
a.FlavorColors[key] = colors
|
||||
} else {
|
||||
mErr = errors.Join(mErr, fmt.Errorf("failed to unmarshal flavor colors for key %s: %w", key, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
return mErr
|
||||
}
|
||||
|
||||
func (a ThemeAccent) MarshalJSON() ([]byte, error) {
|
||||
m := map[string]any{
|
||||
"id": a.ID,
|
||||
"name": a.Name,
|
||||
}
|
||||
for k, v := range a.FlavorColors {
|
||||
m[k] = v
|
||||
}
|
||||
return json.Marshal(m)
|
||||
}
|
||||
|
||||
type MultiVariantDefaults struct {
|
||||
Dark map[string]string `json:"dark,omitempty"`
|
||||
Light map[string]string `json:"light,omitempty"`
|
||||
}
|
||||
|
||||
type ThemeVariants struct {
|
||||
Default string `json:"default,omitempty"`
|
||||
Options []ThemeVariant `json:"options,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Default string `json:"default,omitempty"`
|
||||
Defaults *MultiVariantDefaults `json:"defaults,omitempty"`
|
||||
Options []ThemeVariant `json:"options,omitempty"`
|
||||
Flavors []ThemeFlavor `json:"flavors,omitempty"`
|
||||
Accents []ThemeAccent `json:"accents,omitempty"`
|
||||
}
|
||||
|
||||
type Theme struct {
|
||||
|
||||
@@ -1560,7 +1560,10 @@ Singleton {
|
||||
}
|
||||
|
||||
function getRegistryThemeVariant(themeId, defaultVariant) {
|
||||
return registryThemeVariants[themeId] || defaultVariant || "";
|
||||
var stored = registryThemeVariants[themeId];
|
||||
if (typeof stored === "string")
|
||||
return stored || defaultVariant || "";
|
||||
return defaultVariant || "";
|
||||
}
|
||||
|
||||
function setRegistryThemeVariant(themeId, variantId) {
|
||||
@@ -1572,6 +1575,25 @@ Singleton {
|
||||
Theme.reloadCustomThemeVariant();
|
||||
}
|
||||
|
||||
function getRegistryThemeMultiVariant(themeId, defaults) {
|
||||
var stored = registryThemeVariants[themeId];
|
||||
if (stored && typeof stored === "object")
|
||||
return stored;
|
||||
return defaults || {};
|
||||
}
|
||||
|
||||
function setRegistryThemeMultiVariant(themeId, flavor, accent) {
|
||||
var variants = JSON.parse(JSON.stringify(registryThemeVariants));
|
||||
variants[themeId] = {
|
||||
flavor: flavor,
|
||||
accent: accent
|
||||
};
|
||||
registryThemeVariants = variants;
|
||||
saveSettings();
|
||||
if (typeof Theme !== "undefined")
|
||||
Theme.reloadCustomThemeVariant();
|
||||
}
|
||||
|
||||
function toggleDankBarVisible() {
|
||||
const defaultBar = barConfigs[0] || getBarConfig("default");
|
||||
if (defaultBar) {
|
||||
|
||||
@@ -1,545 +1,430 @@
|
||||
// Stock theme definitions for DankMaterialShell
|
||||
// Separated from Theme.qml to keep that file clean
|
||||
|
||||
const CatppuccinMocha = {
|
||||
surface: "#181825",
|
||||
surfaceText: "#cdd6f4",
|
||||
surfaceVariant: "#1e1e2e",
|
||||
surfaceVariantText: "#a6adc8",
|
||||
background: "#181825",
|
||||
backgroundText: "#cdd6f4",
|
||||
outline: "#6c7086",
|
||||
surfaceContainer: "#1e1e2e",
|
||||
surfaceContainerHigh: "#313244",
|
||||
surfaceContainerHighest: "#45475a"
|
||||
}
|
||||
|
||||
const CatppuccinLatte = {
|
||||
surface: "#e6e9ef",
|
||||
surfaceText: "#4c4f69",
|
||||
surfaceVariant: "#e6e9ef",
|
||||
surfaceVariantText: "#6c6f85",
|
||||
background: "#eff1f5",
|
||||
backgroundText: "#4c4f69",
|
||||
outline: "#9ca0b0",
|
||||
surfaceContainer: "#dce0e8",
|
||||
surfaceContainerHigh: "#ccd0da",
|
||||
surfaceContainerHighest: "#bcc0cc"
|
||||
}
|
||||
|
||||
const CatppuccinVariants = {
|
||||
"cat-rosewater": {
|
||||
name: "Rosewater",
|
||||
dark: { primary: "#f5e0dc", secondary: "#f2cdcd", primaryText: "#1e1e2e", primaryContainer: "#7d5d56", surfaceTint: "#f5e0dc" },
|
||||
light: { primary: "#dc8a78", secondary: "#dd7878", primaryText: "#ffffff", primaryContainer: "#f6e7e3", surfaceTint: "#dc8a78" }
|
||||
},
|
||||
"cat-flamingo": {
|
||||
name: "Flamingo",
|
||||
dark: { primary: "#f2cdcd", secondary: "#f5e0dc", primaryText: "#1e1e2e", primaryContainer: "#7a555a", surfaceTint: "#f2cdcd" },
|
||||
light: { primary: "#dd7878", secondary: "#dc8a78", primaryText: "#ffffff", primaryContainer: "#f6e5e5", surfaceTint: "#dd7878" }
|
||||
},
|
||||
"cat-pink": {
|
||||
name: "Pink",
|
||||
dark: { primary: "#f5c2e7", secondary: "#cba6f7", primaryText: "#1e1e2e", primaryContainer: "#7a3f69", surfaceTint: "#f5c2e7" },
|
||||
light: { primary: "#ea76cb", secondary: "#8839ef", primaryText: "#ffffff", primaryContainer: "#f7d7ee", surfaceTint: "#ea76cb" }
|
||||
},
|
||||
"cat-mauve": {
|
||||
name: "Mauve",
|
||||
dark: { primary: "#cba6f7", secondary: "#b4befe", primaryText: "#1e1e2e", primaryContainer: "#55307f", surfaceTint: "#cba6f7" },
|
||||
light: { primary: "#8839ef", secondary: "#7287fd", primaryText: "#ffffff", primaryContainer: "#eadcff", surfaceTint: "#8839ef" }
|
||||
},
|
||||
"cat-red": {
|
||||
name: "Red",
|
||||
dark: { primary: "#f38ba8", secondary: "#eba0ac", primaryText: "#1e1e2e", primaryContainer: "#6f2438", surfaceTint: "#f38ba8" },
|
||||
light: { primary: "#d20f39", secondary: "#e64553", primaryText: "#ffffff", primaryContainer: "#f6d0d6", surfaceTint: "#d20f39" }
|
||||
},
|
||||
"cat-maroon": {
|
||||
name: "Maroon",
|
||||
dark: { primary: "#eba0ac", secondary: "#f38ba8", primaryText: "#1e1e2e", primaryContainer: "#6d3641", surfaceTint: "#eba0ac" },
|
||||
light: { primary: "#e64553", secondary: "#d20f39", primaryText: "#ffffff", primaryContainer: "#f7d8dc", surfaceTint: "#e64553" }
|
||||
},
|
||||
"cat-peach": {
|
||||
name: "Peach",
|
||||
dark: { primary: "#fab387", secondary: "#f9e2af", primaryText: "#1e1e2e", primaryContainer: "#734226", surfaceTint: "#fab387" },
|
||||
light: { primary: "#fe640b", secondary: "#df8e1d", primaryText: "#ffffff", primaryContainer: "#ffe4d5", surfaceTint: "#fe640b" }
|
||||
},
|
||||
"cat-yellow": {
|
||||
name: "Yellow",
|
||||
dark: { primary: "#f9e2af", secondary: "#a6e3a1", primaryText: "#1e1e2e", primaryContainer: "#6e5a2f", surfaceTint: "#f9e2af" },
|
||||
light: { primary: "#df8e1d", secondary: "#40a02b", primaryText: "#ffffff", primaryContainer: "#fff6d6", surfaceTint: "#df8e1d" }
|
||||
},
|
||||
"cat-green": {
|
||||
name: "Green",
|
||||
dark: { primary: "#a6e3a1", secondary: "#94e2d5", primaryText: "#1e1e2e", primaryContainer: "#2f5f36", surfaceTint: "#a6e3a1" },
|
||||
light: { primary: "#40a02b", secondary: "#179299", primaryText: "#ffffff", primaryContainer: "#dff4e0", surfaceTint: "#40a02b" }
|
||||
},
|
||||
"cat-teal": {
|
||||
name: "Teal",
|
||||
dark: { primary: "#94e2d5", secondary: "#89dceb", primaryText: "#1e1e2e", primaryContainer: "#2e5e59", surfaceTint: "#94e2d5" },
|
||||
light: { primary: "#179299", secondary: "#04a5e5", primaryText: "#ffffff", primaryContainer: "#daf3f1", surfaceTint: "#179299" }
|
||||
},
|
||||
"cat-sky": {
|
||||
name: "Sky",
|
||||
dark: { primary: "#89dceb", secondary: "#74c7ec", primaryText: "#1e1e2e", primaryContainer: "#24586a", surfaceTint: "#89dceb" },
|
||||
light: { primary: "#04a5e5", secondary: "#209fb5", primaryText: "#ffffff", primaryContainer: "#dbf1fb", surfaceTint: "#04a5e5" }
|
||||
},
|
||||
"cat-sapphire": {
|
||||
name: "Sapphire",
|
||||
dark: { primary: "#74c7ec", secondary: "#89b4fa", primaryText: "#1e1e2e", primaryContainer: "#1f4d6f", surfaceTint: "#74c7ec" },
|
||||
light: { primary: "#209fb5", secondary: "#1e66f5", primaryText: "#ffffff", primaryContainer: "#def3f8", surfaceTint: "#209fb5" }
|
||||
},
|
||||
"cat-blue": {
|
||||
name: "Blue",
|
||||
dark: { primary: "#89b4fa", secondary: "#b4befe", primaryText: "#1e1e2e", primaryContainer: "#243f75", surfaceTint: "#89b4fa" },
|
||||
light: { primary: "#1e66f5", secondary: "#7287fd", primaryText: "#ffffff", primaryContainer: "#e0e9ff", surfaceTint: "#1e66f5" }
|
||||
},
|
||||
"cat-lavender": {
|
||||
name: "Lavender",
|
||||
dark: { primary: "#b4befe", secondary: "#cba6f7", primaryText: "#1e1e2e", primaryContainer: "#3f4481", surfaceTint: "#b4befe" },
|
||||
light: { primary: "#7287fd", secondary: "#8839ef", primaryText: "#ffffff", primaryContainer: "#e5e8ff", surfaceTint: "#7287fd" }
|
||||
}
|
||||
}
|
||||
|
||||
function getCatppuccinTheme(variant, isLight = false) {
|
||||
const variantData = CatppuccinVariants[variant]
|
||||
if (!variantData) return null
|
||||
|
||||
const baseColors = isLight ? CatppuccinLatte : CatppuccinMocha
|
||||
const accentColors = isLight ? variantData.light : variantData.dark
|
||||
|
||||
return Object.assign({
|
||||
name: `${variantData.name}${isLight ? ' Light' : ''}`
|
||||
}, baseColors, accentColors)
|
||||
}
|
||||
|
||||
const StockThemes = {
|
||||
DARK: {
|
||||
blue: {
|
||||
name: "Blue",
|
||||
primary: "#42a5f5",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#0d47a1",
|
||||
secondary: "#8ab4f8",
|
||||
surface: "#101418",
|
||||
surfaceText: "#e0e2e8",
|
||||
surfaceVariant: "#42474e",
|
||||
surfaceVariantText: "#c2c7cf",
|
||||
surfaceTint: "#8ab4f8",
|
||||
background: "#101418",
|
||||
backgroundText: "#e0e2e8",
|
||||
outline: "#8c9199",
|
||||
surfaceContainer: "#1d2024",
|
||||
surfaceContainerHigh: "#272a2f",
|
||||
surfaceContainerHighest: "#32353a"
|
||||
},
|
||||
purple: {
|
||||
name: "Purple",
|
||||
primary: "#D0BCFF",
|
||||
primaryText: "#381E72",
|
||||
primaryContainer: "#4F378B",
|
||||
secondary: "#CCC2DC",
|
||||
surface: "#141218",
|
||||
surfaceText: "#e6e0e9",
|
||||
surfaceVariant: "#49454e",
|
||||
surfaceVariantText: "#cac4cf",
|
||||
surfaceTint: "#D0BCFF",
|
||||
background: "#141218",
|
||||
backgroundText: "#e6e0e9",
|
||||
outline: "#948f99",
|
||||
surfaceContainer: "#211f24",
|
||||
surfaceContainerHigh: "#2b292f",
|
||||
surfaceContainerHighest: "#36343a"
|
||||
},
|
||||
green: {
|
||||
name: "Green",
|
||||
primary: "#4caf50",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#1b5e20",
|
||||
secondary: "#81c995",
|
||||
surface: "#10140f",
|
||||
surfaceText: "#e0e4db",
|
||||
surfaceVariant: "#424940",
|
||||
surfaceVariantText: "#c2c9bd",
|
||||
surfaceTint: "#81c995",
|
||||
background: "#10140f",
|
||||
backgroundText: "#e0e4db",
|
||||
outline: "#8c9388",
|
||||
surfaceContainer: "#1d211b",
|
||||
surfaceContainerHigh: "#272b25",
|
||||
surfaceContainerHighest: "#323630"
|
||||
},
|
||||
orange: {
|
||||
name: "Orange",
|
||||
primary: "#ff6d00",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#3e2723",
|
||||
secondary: "#ffb74d",
|
||||
surface: "#1a120e",
|
||||
surfaceText: "#f0dfd8",
|
||||
surfaceVariant: "#52443d",
|
||||
surfaceVariantText: "#d7c2b9",
|
||||
surfaceTint: "#ffb74d",
|
||||
background: "#1a120e",
|
||||
backgroundText: "#f0dfd8",
|
||||
outline: "#a08d85",
|
||||
surfaceContainer: "#271e1a",
|
||||
surfaceContainerHigh: "#322824",
|
||||
surfaceContainerHighest: "#3d332e"
|
||||
},
|
||||
red: {
|
||||
name: "Red",
|
||||
primary: "#f44336",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#4a0e0e",
|
||||
secondary: "#f28b82",
|
||||
surface: "#1a1110",
|
||||
surfaceText: "#f1dedc",
|
||||
surfaceVariant: "#534341",
|
||||
surfaceVariantText: "#d8c2be",
|
||||
surfaceTint: "#f28b82",
|
||||
background: "#1a1110",
|
||||
backgroundText: "#f1dedc",
|
||||
outline: "#a08c89",
|
||||
surfaceContainer: "#271d1c",
|
||||
surfaceContainerHigh: "#322826",
|
||||
surfaceContainerHighest: "#3d3231"
|
||||
},
|
||||
cyan: {
|
||||
name: "Cyan",
|
||||
primary: "#00bcd4",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#004d5c",
|
||||
secondary: "#4dd0e1",
|
||||
surface: "#0e1416",
|
||||
surfaceText: "#dee3e5",
|
||||
surfaceVariant: "#3f484a",
|
||||
surfaceVariantText: "#bfc8ca",
|
||||
surfaceTint: "#4dd0e1",
|
||||
background: "#0e1416",
|
||||
backgroundText: "#dee3e5",
|
||||
outline: "#899295",
|
||||
surfaceContainer: "#1b2122",
|
||||
surfaceContainerHigh: "#252b2c",
|
||||
surfaceContainerHighest: "#303637"
|
||||
},
|
||||
pink: {
|
||||
name: "Pink",
|
||||
primary: "#e91e63",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#4a0e2f",
|
||||
secondary: "#f8bbd9",
|
||||
surface: "#191112",
|
||||
surfaceText: "#f0dee0",
|
||||
surfaceVariant: "#524345",
|
||||
surfaceVariantText: "#d6c2c3",
|
||||
surfaceTint: "#f8bbd9",
|
||||
background: "#191112",
|
||||
backgroundText: "#f0dee0",
|
||||
outline: "#9f8c8e",
|
||||
surfaceContainer: "#261d1e",
|
||||
surfaceContainerHigh: "#312829",
|
||||
surfaceContainerHighest: "#3c3233"
|
||||
},
|
||||
amber: {
|
||||
name: "Amber",
|
||||
primary: "#ffc107",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#4a3c00",
|
||||
secondary: "#ffd54f",
|
||||
surface: "#17130b",
|
||||
surfaceText: "#ebe1d4",
|
||||
surfaceVariant: "#4d4639",
|
||||
surfaceVariantText: "#d0c5b4",
|
||||
surfaceTint: "#ffd54f",
|
||||
background: "#17130b",
|
||||
backgroundText: "#ebe1d4",
|
||||
outline: "#998f80",
|
||||
surfaceContainer: "#231f17",
|
||||
surfaceContainerHigh: "#2e2921",
|
||||
surfaceContainerHighest: "#39342b"
|
||||
},
|
||||
coral: {
|
||||
name: "Coral",
|
||||
primary: "#ffb4ab",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#8c1d18",
|
||||
secondary: "#f9dedc",
|
||||
surface: "#1a1110",
|
||||
surfaceText: "#f1dedc",
|
||||
surfaceVariant: "#534341",
|
||||
surfaceVariantText: "#d8c2bf",
|
||||
surfaceTint: "#ffb4ab",
|
||||
background: "#1a1110",
|
||||
backgroundText: "#f1dedc",
|
||||
outline: "#a08c8a",
|
||||
surfaceContainer: "#271d1c",
|
||||
surfaceContainerHigh: "#322826",
|
||||
surfaceContainerHighest: "#3d3231"
|
||||
},
|
||||
monochrome: {
|
||||
name: "Monochrome",
|
||||
primary: "#ffffff",
|
||||
primaryText: "#2b303c",
|
||||
primaryContainer: "#424753",
|
||||
secondary: "#c4c6d0",
|
||||
surface: "#2a2a2a",
|
||||
surfaceText: "#e4e2e3",
|
||||
surfaceVariant: "#474648",
|
||||
surfaceVariantText: "#c8c6c7",
|
||||
surfaceTint: "#c2c6d6",
|
||||
background: "#131315",
|
||||
backgroundText: "#e4e2e3",
|
||||
outline: "#929092",
|
||||
surfaceContainer: "#353535",
|
||||
surfaceContainerHigh: "#424242",
|
||||
surfaceContainerHighest: "#505050",
|
||||
error: "#ffb4ab",
|
||||
warning: "#3f4759",
|
||||
info: "#595e6c",
|
||||
matugen_type: "scheme-monochrome"
|
||||
}
|
||||
DARK: {
|
||||
blue: {
|
||||
name: "Blue",
|
||||
primary: "#42a5f5",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#0d47a1",
|
||||
secondary: "#8ab4f8",
|
||||
surface: "#101418",
|
||||
surfaceText: "#e0e2e8",
|
||||
surfaceVariant: "#42474e",
|
||||
surfaceVariantText: "#c2c7cf",
|
||||
surfaceTint: "#8ab4f8",
|
||||
background: "#101418",
|
||||
backgroundText: "#e0e2e8",
|
||||
outline: "#8c9199",
|
||||
surfaceContainer: "#1d2024",
|
||||
surfaceContainerHigh: "#272a2f",
|
||||
surfaceContainerHighest: "#32353a",
|
||||
},
|
||||
LIGHT: {
|
||||
blue: {
|
||||
name: "Blue Light",
|
||||
primary: "#1976d2",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#e3f2fd",
|
||||
secondary: "#42a5f5",
|
||||
surface: "#f7f9ff",
|
||||
surfaceText: "#181c20",
|
||||
surfaceVariant: "#dee3eb",
|
||||
surfaceVariantText: "#42474e",
|
||||
surfaceTint: "#1976d2",
|
||||
background: "#f7f9ff",
|
||||
backgroundText: "#181c20",
|
||||
outline: "#72777f",
|
||||
surfaceContainer: "#eceef4",
|
||||
surfaceContainerHigh: "#e6e8ee",
|
||||
surfaceContainerHighest: "#e0e2e8"
|
||||
},
|
||||
purple: {
|
||||
name: "Purple Light",
|
||||
primary: "#6750A4",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#EADDFF",
|
||||
secondary: "#625B71",
|
||||
surface: "#fef7ff",
|
||||
surfaceText: "#1d1b20",
|
||||
surfaceVariant: "#e7e0eb",
|
||||
surfaceVariantText: "#49454e",
|
||||
surfaceTint: "#6750A4",
|
||||
background: "#fef7ff",
|
||||
backgroundText: "#1d1b20",
|
||||
outline: "#7a757f",
|
||||
surfaceContainer: "#f2ecf4",
|
||||
surfaceContainerHigh: "#ece6ee",
|
||||
surfaceContainerHighest: "#e6e0e9"
|
||||
},
|
||||
green: {
|
||||
name: "Green Light",
|
||||
primary: "#2e7d32",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#e8f5e8",
|
||||
secondary: "#4caf50",
|
||||
surface: "#f7fbf1",
|
||||
surfaceText: "#191d17",
|
||||
surfaceVariant: "#dee5d8",
|
||||
surfaceVariantText: "#424940",
|
||||
surfaceTint: "#2e7d32",
|
||||
background: "#f7fbf1",
|
||||
backgroundText: "#191d17",
|
||||
outline: "#72796f",
|
||||
surfaceContainer: "#ecefe6",
|
||||
surfaceContainerHigh: "#e6e9e0",
|
||||
surfaceContainerHighest: "#e0e4db"
|
||||
},
|
||||
orange: {
|
||||
name: "Orange Light",
|
||||
primary: "#e65100",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#ffecb3",
|
||||
secondary: "#ff9800",
|
||||
surface: "#fff8f6",
|
||||
surfaceText: "#221a16",
|
||||
surfaceVariant: "#f4ded5",
|
||||
surfaceVariantText: "#52443d",
|
||||
surfaceTint: "#e65100",
|
||||
background: "#fff8f6",
|
||||
backgroundText: "#221a16",
|
||||
outline: "#85736c",
|
||||
surfaceContainer: "#fceae3",
|
||||
surfaceContainerHigh: "#f6e5de",
|
||||
surfaceContainerHighest: "#f0dfd8"
|
||||
},
|
||||
red: {
|
||||
name: "Red Light",
|
||||
primary: "#d32f2f",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#ffebee",
|
||||
secondary: "#f44336",
|
||||
surface: "#fff8f7",
|
||||
surfaceText: "#231918",
|
||||
surfaceVariant: "#f5ddda",
|
||||
surfaceVariantText: "#534341",
|
||||
surfaceTint: "#d32f2f",
|
||||
background: "#fff8f7",
|
||||
backgroundText: "#231918",
|
||||
outline: "#857370",
|
||||
surfaceContainer: "#fceae7",
|
||||
surfaceContainerHigh: "#f7e4e1",
|
||||
surfaceContainerHighest: "#f1dedc"
|
||||
},
|
||||
cyan: {
|
||||
name: "Cyan Light",
|
||||
primary: "#0097a7",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#e0f2f1",
|
||||
secondary: "#00bcd4",
|
||||
surface: "#f5fafc",
|
||||
surfaceText: "#171d1e",
|
||||
surfaceVariant: "#dbe4e6",
|
||||
surfaceVariantText: "#3f484a",
|
||||
surfaceTint: "#0097a7",
|
||||
background: "#f5fafc",
|
||||
backgroundText: "#171d1e",
|
||||
outline: "#6f797b",
|
||||
surfaceContainer: "#e9eff0",
|
||||
surfaceContainerHigh: "#e3e9eb",
|
||||
surfaceContainerHighest: "#dee3e5"
|
||||
},
|
||||
pink: {
|
||||
name: "Pink Light",
|
||||
primary: "#c2185b",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#fce4ec",
|
||||
secondary: "#e91e63",
|
||||
surface: "#fff8f7",
|
||||
surfaceText: "#22191a",
|
||||
surfaceVariant: "#f3dddf",
|
||||
surfaceVariantText: "#524345",
|
||||
surfaceTint: "#c2185b",
|
||||
background: "#fff8f7",
|
||||
backgroundText: "#22191a",
|
||||
outline: "#847375",
|
||||
surfaceContainer: "#fbeaeb",
|
||||
surfaceContainerHigh: "#f5e4e5",
|
||||
surfaceContainerHighest: "#f0dee0"
|
||||
},
|
||||
amber: {
|
||||
name: "Amber Light",
|
||||
primary: "#ff8f00",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#fff8e1",
|
||||
secondary: "#ffc107",
|
||||
surface: "#fff8f2",
|
||||
surfaceText: "#1f1b13",
|
||||
surfaceVariant: "#ede1cf",
|
||||
surfaceVariantText: "#4d4639",
|
||||
surfaceTint: "#ff8f00",
|
||||
background: "#fff8f2",
|
||||
backgroundText: "#1f1b13",
|
||||
outline: "#7f7667",
|
||||
surfaceContainer: "#f6ecdf",
|
||||
surfaceContainerHigh: "#f1e7d9",
|
||||
surfaceContainerHighest: "#ebe1d4"
|
||||
},
|
||||
coral: {
|
||||
name: "Coral Light",
|
||||
primary: "#8c1d18",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#ffdad6",
|
||||
secondary: "#ff5449",
|
||||
surface: "#fff8f7",
|
||||
surfaceText: "#231918",
|
||||
surfaceVariant: "#f5ddda",
|
||||
surfaceVariantText: "#534341",
|
||||
surfaceTint: "#8c1d18",
|
||||
background: "#fff8f7",
|
||||
backgroundText: "#231918",
|
||||
outline: "#857371",
|
||||
surfaceContainer: "#fceae7",
|
||||
surfaceContainerHigh: "#f6e4e2",
|
||||
surfaceContainerHighest: "#f1dedc"
|
||||
},
|
||||
monochrome: {
|
||||
name: "Monochrome Light",
|
||||
primary: "#2b303c",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#d6d7dc",
|
||||
secondary: "#4a4d56",
|
||||
surface: "#f5f5f6",
|
||||
surfaceText: "#2a2a2a",
|
||||
surfaceVariant: "#e0e0e2",
|
||||
surfaceVariantText: "#424242",
|
||||
surfaceTint: "#5a5f6e",
|
||||
background: "#ffffff",
|
||||
backgroundText: "#1a1a1a",
|
||||
outline: "#757577",
|
||||
surfaceContainer: "#e8e8ea",
|
||||
surfaceContainerHigh: "#dcdcde",
|
||||
surfaceContainerHighest: "#d0d0d2",
|
||||
error: "#ba1a1a",
|
||||
warning: "#f9e79f",
|
||||
info: "#5d6475",
|
||||
matugen_type: "scheme-monochrome"
|
||||
}
|
||||
}
|
||||
}
|
||||
purple: {
|
||||
name: "Purple",
|
||||
primary: "#D0BCFF",
|
||||
primaryText: "#381E72",
|
||||
primaryContainer: "#4F378B",
|
||||
secondary: "#CCC2DC",
|
||||
surface: "#141218",
|
||||
surfaceText: "#e6e0e9",
|
||||
surfaceVariant: "#49454e",
|
||||
surfaceVariantText: "#cac4cf",
|
||||
surfaceTint: "#D0BCFF",
|
||||
background: "#141218",
|
||||
backgroundText: "#e6e0e9",
|
||||
outline: "#948f99",
|
||||
surfaceContainer: "#211f24",
|
||||
surfaceContainerHigh: "#2b292f",
|
||||
surfaceContainerHighest: "#36343a",
|
||||
},
|
||||
green: {
|
||||
name: "Green",
|
||||
primary: "#4caf50",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#1b5e20",
|
||||
secondary: "#81c995",
|
||||
surface: "#10140f",
|
||||
surfaceText: "#e0e4db",
|
||||
surfaceVariant: "#424940",
|
||||
surfaceVariantText: "#c2c9bd",
|
||||
surfaceTint: "#81c995",
|
||||
background: "#10140f",
|
||||
backgroundText: "#e0e4db",
|
||||
outline: "#8c9388",
|
||||
surfaceContainer: "#1d211b",
|
||||
surfaceContainerHigh: "#272b25",
|
||||
surfaceContainerHighest: "#323630",
|
||||
},
|
||||
orange: {
|
||||
name: "Orange",
|
||||
primary: "#ff6d00",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#3e2723",
|
||||
secondary: "#ffb74d",
|
||||
surface: "#1a120e",
|
||||
surfaceText: "#f0dfd8",
|
||||
surfaceVariant: "#52443d",
|
||||
surfaceVariantText: "#d7c2b9",
|
||||
surfaceTint: "#ffb74d",
|
||||
background: "#1a120e",
|
||||
backgroundText: "#f0dfd8",
|
||||
outline: "#a08d85",
|
||||
surfaceContainer: "#271e1a",
|
||||
surfaceContainerHigh: "#322824",
|
||||
surfaceContainerHighest: "#3d332e",
|
||||
},
|
||||
red: {
|
||||
name: "Red",
|
||||
primary: "#f44336",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#4a0e0e",
|
||||
secondary: "#f28b82",
|
||||
surface: "#1a1110",
|
||||
surfaceText: "#f1dedc",
|
||||
surfaceVariant: "#534341",
|
||||
surfaceVariantText: "#d8c2be",
|
||||
surfaceTint: "#f28b82",
|
||||
background: "#1a1110",
|
||||
backgroundText: "#f1dedc",
|
||||
outline: "#a08c89",
|
||||
surfaceContainer: "#271d1c",
|
||||
surfaceContainerHigh: "#322826",
|
||||
surfaceContainerHighest: "#3d3231",
|
||||
},
|
||||
cyan: {
|
||||
name: "Cyan",
|
||||
primary: "#00bcd4",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#004d5c",
|
||||
secondary: "#4dd0e1",
|
||||
surface: "#0e1416",
|
||||
surfaceText: "#dee3e5",
|
||||
surfaceVariant: "#3f484a",
|
||||
surfaceVariantText: "#bfc8ca",
|
||||
surfaceTint: "#4dd0e1",
|
||||
background: "#0e1416",
|
||||
backgroundText: "#dee3e5",
|
||||
outline: "#899295",
|
||||
surfaceContainer: "#1b2122",
|
||||
surfaceContainerHigh: "#252b2c",
|
||||
surfaceContainerHighest: "#303637",
|
||||
},
|
||||
pink: {
|
||||
name: "Pink",
|
||||
primary: "#e91e63",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#4a0e2f",
|
||||
secondary: "#f8bbd9",
|
||||
surface: "#191112",
|
||||
surfaceText: "#f0dee0",
|
||||
surfaceVariant: "#524345",
|
||||
surfaceVariantText: "#d6c2c3",
|
||||
surfaceTint: "#f8bbd9",
|
||||
background: "#191112",
|
||||
backgroundText: "#f0dee0",
|
||||
outline: "#9f8c8e",
|
||||
surfaceContainer: "#261d1e",
|
||||
surfaceContainerHigh: "#312829",
|
||||
surfaceContainerHighest: "#3c3233",
|
||||
},
|
||||
amber: {
|
||||
name: "Amber",
|
||||
primary: "#ffc107",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#4a3c00",
|
||||
secondary: "#ffd54f",
|
||||
surface: "#17130b",
|
||||
surfaceText: "#ebe1d4",
|
||||
surfaceVariant: "#4d4639",
|
||||
surfaceVariantText: "#d0c5b4",
|
||||
surfaceTint: "#ffd54f",
|
||||
background: "#17130b",
|
||||
backgroundText: "#ebe1d4",
|
||||
outline: "#998f80",
|
||||
surfaceContainer: "#231f17",
|
||||
surfaceContainerHigh: "#2e2921",
|
||||
surfaceContainerHighest: "#39342b",
|
||||
},
|
||||
coral: {
|
||||
name: "Coral",
|
||||
primary: "#ffb4ab",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#8c1d18",
|
||||
secondary: "#f9dedc",
|
||||
surface: "#1a1110",
|
||||
surfaceText: "#f1dedc",
|
||||
surfaceVariant: "#534341",
|
||||
surfaceVariantText: "#d8c2bf",
|
||||
surfaceTint: "#ffb4ab",
|
||||
background: "#1a1110",
|
||||
backgroundText: "#f1dedc",
|
||||
outline: "#a08c8a",
|
||||
surfaceContainer: "#271d1c",
|
||||
surfaceContainerHigh: "#322826",
|
||||
surfaceContainerHighest: "#3d3231",
|
||||
},
|
||||
monochrome: {
|
||||
name: "Monochrome",
|
||||
primary: "#ffffff",
|
||||
primaryText: "#2b303c",
|
||||
primaryContainer: "#424753",
|
||||
secondary: "#c4c6d0",
|
||||
surface: "#2a2a2a",
|
||||
surfaceText: "#e4e2e3",
|
||||
surfaceVariant: "#474648",
|
||||
surfaceVariantText: "#c8c6c7",
|
||||
surfaceTint: "#c2c6d6",
|
||||
background: "#131315",
|
||||
backgroundText: "#e4e2e3",
|
||||
outline: "#929092",
|
||||
surfaceContainer: "#353535",
|
||||
surfaceContainerHigh: "#424242",
|
||||
surfaceContainerHighest: "#505050",
|
||||
error: "#ffb4ab",
|
||||
warning: "#3f4759",
|
||||
info: "#595e6c",
|
||||
matugen_type: "scheme-monochrome",
|
||||
},
|
||||
},
|
||||
LIGHT: {
|
||||
blue: {
|
||||
name: "Blue Light",
|
||||
primary: "#1976d2",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#e3f2fd",
|
||||
secondary: "#42a5f5",
|
||||
surface: "#f7f9ff",
|
||||
surfaceText: "#181c20",
|
||||
surfaceVariant: "#dee3eb",
|
||||
surfaceVariantText: "#42474e",
|
||||
surfaceTint: "#1976d2",
|
||||
background: "#f7f9ff",
|
||||
backgroundText: "#181c20",
|
||||
outline: "#72777f",
|
||||
surfaceContainer: "#eceef4",
|
||||
surfaceContainerHigh: "#e6e8ee",
|
||||
surfaceContainerHighest: "#e0e2e8",
|
||||
},
|
||||
purple: {
|
||||
name: "Purple Light",
|
||||
primary: "#6750A4",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#EADDFF",
|
||||
secondary: "#625B71",
|
||||
surface: "#fef7ff",
|
||||
surfaceText: "#1d1b20",
|
||||
surfaceVariant: "#e7e0eb",
|
||||
surfaceVariantText: "#49454e",
|
||||
surfaceTint: "#6750A4",
|
||||
background: "#fef7ff",
|
||||
backgroundText: "#1d1b20",
|
||||
outline: "#7a757f",
|
||||
surfaceContainer: "#f2ecf4",
|
||||
surfaceContainerHigh: "#ece6ee",
|
||||
surfaceContainerHighest: "#e6e0e9",
|
||||
},
|
||||
green: {
|
||||
name: "Green Light",
|
||||
primary: "#2e7d32",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#e8f5e8",
|
||||
secondary: "#4caf50",
|
||||
surface: "#f7fbf1",
|
||||
surfaceText: "#191d17",
|
||||
surfaceVariant: "#dee5d8",
|
||||
surfaceVariantText: "#424940",
|
||||
surfaceTint: "#2e7d32",
|
||||
background: "#f7fbf1",
|
||||
backgroundText: "#191d17",
|
||||
outline: "#72796f",
|
||||
surfaceContainer: "#ecefe6",
|
||||
surfaceContainerHigh: "#e6e9e0",
|
||||
surfaceContainerHighest: "#e0e4db",
|
||||
},
|
||||
orange: {
|
||||
name: "Orange Light",
|
||||
primary: "#e65100",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#ffecb3",
|
||||
secondary: "#ff9800",
|
||||
surface: "#fff8f6",
|
||||
surfaceText: "#221a16",
|
||||
surfaceVariant: "#f4ded5",
|
||||
surfaceVariantText: "#52443d",
|
||||
surfaceTint: "#e65100",
|
||||
background: "#fff8f6",
|
||||
backgroundText: "#221a16",
|
||||
outline: "#85736c",
|
||||
surfaceContainer: "#fceae3",
|
||||
surfaceContainerHigh: "#f6e5de",
|
||||
surfaceContainerHighest: "#f0dfd8",
|
||||
},
|
||||
red: {
|
||||
name: "Red Light",
|
||||
primary: "#d32f2f",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#ffebee",
|
||||
secondary: "#f44336",
|
||||
surface: "#fff8f7",
|
||||
surfaceText: "#231918",
|
||||
surfaceVariant: "#f5ddda",
|
||||
surfaceVariantText: "#534341",
|
||||
surfaceTint: "#d32f2f",
|
||||
background: "#fff8f7",
|
||||
backgroundText: "#231918",
|
||||
outline: "#857370",
|
||||
surfaceContainer: "#fceae7",
|
||||
surfaceContainerHigh: "#f7e4e1",
|
||||
surfaceContainerHighest: "#f1dedc",
|
||||
},
|
||||
cyan: {
|
||||
name: "Cyan Light",
|
||||
primary: "#0097a7",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#e0f2f1",
|
||||
secondary: "#00bcd4",
|
||||
surface: "#f5fafc",
|
||||
surfaceText: "#171d1e",
|
||||
surfaceVariant: "#dbe4e6",
|
||||
surfaceVariantText: "#3f484a",
|
||||
surfaceTint: "#0097a7",
|
||||
background: "#f5fafc",
|
||||
backgroundText: "#171d1e",
|
||||
outline: "#6f797b",
|
||||
surfaceContainer: "#e9eff0",
|
||||
surfaceContainerHigh: "#e3e9eb",
|
||||
surfaceContainerHighest: "#dee3e5",
|
||||
},
|
||||
pink: {
|
||||
name: "Pink Light",
|
||||
primary: "#c2185b",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#fce4ec",
|
||||
secondary: "#e91e63",
|
||||
surface: "#fff8f7",
|
||||
surfaceText: "#22191a",
|
||||
surfaceVariant: "#f3dddf",
|
||||
surfaceVariantText: "#524345",
|
||||
surfaceTint: "#c2185b",
|
||||
background: "#fff8f7",
|
||||
backgroundText: "#22191a",
|
||||
outline: "#847375",
|
||||
surfaceContainer: "#fbeaeb",
|
||||
surfaceContainerHigh: "#f5e4e5",
|
||||
surfaceContainerHighest: "#f0dee0",
|
||||
},
|
||||
amber: {
|
||||
name: "Amber Light",
|
||||
primary: "#ff8f00",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#fff8e1",
|
||||
secondary: "#ffc107",
|
||||
surface: "#fff8f2",
|
||||
surfaceText: "#1f1b13",
|
||||
surfaceVariant: "#ede1cf",
|
||||
surfaceVariantText: "#4d4639",
|
||||
surfaceTint: "#ff8f00",
|
||||
background: "#fff8f2",
|
||||
backgroundText: "#1f1b13",
|
||||
outline: "#7f7667",
|
||||
surfaceContainer: "#f6ecdf",
|
||||
surfaceContainerHigh: "#f1e7d9",
|
||||
surfaceContainerHighest: "#ebe1d4",
|
||||
},
|
||||
coral: {
|
||||
name: "Coral Light",
|
||||
primary: "#8c1d18",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#ffdad6",
|
||||
secondary: "#ff5449",
|
||||
surface: "#fff8f7",
|
||||
surfaceText: "#231918",
|
||||
surfaceVariant: "#f5ddda",
|
||||
surfaceVariantText: "#534341",
|
||||
surfaceTint: "#8c1d18",
|
||||
background: "#fff8f7",
|
||||
backgroundText: "#231918",
|
||||
outline: "#857371",
|
||||
surfaceContainer: "#fceae7",
|
||||
surfaceContainerHigh: "#f6e4e2",
|
||||
surfaceContainerHighest: "#f1dedc",
|
||||
},
|
||||
monochrome: {
|
||||
name: "Monochrome Light",
|
||||
primary: "#2b303c",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#d6d7dc",
|
||||
secondary: "#4a4d56",
|
||||
surface: "#f5f5f6",
|
||||
surfaceText: "#2a2a2a",
|
||||
surfaceVariant: "#e0e0e2",
|
||||
surfaceVariantText: "#424242",
|
||||
surfaceTint: "#5a5f6e",
|
||||
background: "#ffffff",
|
||||
backgroundText: "#1a1a1a",
|
||||
outline: "#757577",
|
||||
surfaceContainer: "#e8e8ea",
|
||||
surfaceContainerHigh: "#dcdcde",
|
||||
surfaceContainerHighest: "#d0d0d2",
|
||||
error: "#ba1a1a",
|
||||
warning: "#f9e79f",
|
||||
info: "#5d6475",
|
||||
matugen_type: "scheme-monochrome",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const ThemeCategories = {
|
||||
GENERIC: {
|
||||
name: "Generic",
|
||||
variants: ["blue", "purple", "green", "orange", "red", "cyan", "pink", "amber", "coral", "monochrome"]
|
||||
},
|
||||
CATPPUCCIN: {
|
||||
name: "Catppuccin",
|
||||
variants: Object.keys(CatppuccinVariants)
|
||||
}
|
||||
}
|
||||
GENERIC: {
|
||||
name: "Generic",
|
||||
variants: [
|
||||
"blue",
|
||||
"purple",
|
||||
"green",
|
||||
"orange",
|
||||
"red",
|
||||
"cyan",
|
||||
"pink",
|
||||
"amber",
|
||||
"coral",
|
||||
"monochrome",
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const ThemeNames = {
|
||||
BLUE: "blue",
|
||||
PURPLE: "purple",
|
||||
GREEN: "green",
|
||||
ORANGE: "orange",
|
||||
RED: "red",
|
||||
CYAN: "cyan",
|
||||
PINK: "pink",
|
||||
AMBER: "amber",
|
||||
CORAL: "coral",
|
||||
MONOCHROME: "monochrome",
|
||||
DYNAMIC: "dynamic"
|
||||
}
|
||||
BLUE: "blue",
|
||||
PURPLE: "purple",
|
||||
GREEN: "green",
|
||||
ORANGE: "orange",
|
||||
RED: "red",
|
||||
CYAN: "cyan",
|
||||
PINK: "pink",
|
||||
AMBER: "amber",
|
||||
CORAL: "coral",
|
||||
MONOCHROME: "monochrome",
|
||||
DYNAMIC: "dynamic",
|
||||
};
|
||||
|
||||
function isStockTheme(themeName) {
|
||||
return Object.keys(StockThemes.DARK).includes(themeName)
|
||||
}
|
||||
|
||||
function isCatppuccinVariant(themeName) {
|
||||
return Object.keys(CatppuccinVariants).includes(themeName)
|
||||
return Object.keys(StockThemes.DARK).includes(themeName);
|
||||
}
|
||||
|
||||
function getAvailableThemes(isLight = false) {
|
||||
return isLight ? StockThemes.LIGHT : StockThemes.DARK
|
||||
return isLight ? StockThemes.LIGHT : StockThemes.DARK;
|
||||
}
|
||||
|
||||
function getThemeByName(themeName, isLight = false) {
|
||||
if (isCatppuccinVariant(themeName)) {
|
||||
return getCatppuccinTheme(themeName, isLight)
|
||||
}
|
||||
const themes = getAvailableThemes(isLight)
|
||||
return themes[themeName] || themes.blue
|
||||
const themes = getAvailableThemes(isLight);
|
||||
return themes[themeName] || themes.blue;
|
||||
}
|
||||
|
||||
function getAllThemeNames() {
|
||||
return Object.keys(StockThemes.DARK)
|
||||
}
|
||||
|
||||
function getCatppuccinVariantNames() {
|
||||
return Object.keys(CatppuccinVariants)
|
||||
return Object.keys(StockThemes.DARK);
|
||||
}
|
||||
|
||||
function getThemeCategories() {
|
||||
return ThemeCategories
|
||||
return ThemeCategories;
|
||||
}
|
||||
|
||||
@@ -491,11 +491,7 @@ Singleton {
|
||||
} else {
|
||||
currentTheme = themeName;
|
||||
if (currentThemeCategory !== "registry") {
|
||||
if (StockThemes.isCatppuccinVariant(themeName)) {
|
||||
currentThemeCategory = "catppuccin";
|
||||
} else {
|
||||
currentThemeCategory = "generic";
|
||||
}
|
||||
currentThemeCategory = "generic";
|
||||
}
|
||||
}
|
||||
const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode);
|
||||
@@ -564,46 +560,6 @@ Singleton {
|
||||
themeCategoryTransitionTimer.restart();
|
||||
}
|
||||
|
||||
function getCatppuccinColor(variantName) {
|
||||
const catColors = {
|
||||
"cat-rosewater": "#f5e0dc",
|
||||
"cat-flamingo": "#f2cdcd",
|
||||
"cat-pink": "#f5c2e7",
|
||||
"cat-mauve": "#cba6f7",
|
||||
"cat-red": "#f38ba8",
|
||||
"cat-maroon": "#eba0ac",
|
||||
"cat-peach": "#fab387",
|
||||
"cat-yellow": "#f9e2af",
|
||||
"cat-green": "#a6e3a1",
|
||||
"cat-teal": "#94e2d5",
|
||||
"cat-sky": "#89dceb",
|
||||
"cat-sapphire": "#74c7ec",
|
||||
"cat-blue": "#89b4fa",
|
||||
"cat-lavender": "#b4befe"
|
||||
};
|
||||
return catColors[variantName] || "#cba6f7";
|
||||
}
|
||||
|
||||
function getCatppuccinVariantName(variantName) {
|
||||
const catNames = {
|
||||
"cat-rosewater": "Rosewater",
|
||||
"cat-flamingo": "Flamingo",
|
||||
"cat-pink": "Pink",
|
||||
"cat-mauve": "Mauve",
|
||||
"cat-red": "Red",
|
||||
"cat-maroon": "Maroon",
|
||||
"cat-peach": "Peach",
|
||||
"cat-yellow": "Yellow",
|
||||
"cat-green": "Green",
|
||||
"cat-teal": "Teal",
|
||||
"cat-sky": "Sky",
|
||||
"cat-sapphire": "Sapphire",
|
||||
"cat-blue": "Blue",
|
||||
"cat-lavender": "Lavender"
|
||||
};
|
||||
return catNames[variantName] || "Unknown";
|
||||
}
|
||||
|
||||
function loadCustomTheme(themeData) {
|
||||
customThemeRawData = themeData;
|
||||
const colorMode = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "light" : "dark";
|
||||
@@ -615,16 +571,47 @@ Singleton {
|
||||
baseColors = themeData;
|
||||
}
|
||||
|
||||
if (themeData.variants && themeData.variants.options && themeData.variants.options.length > 0) {
|
||||
if (themeData.variants) {
|
||||
const themeId = themeData.id || "";
|
||||
const selectedVariantId = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeVariant(themeId, themeData.variants.default) : themeData.variants.default;
|
||||
const variant = findVariant(themeData.variants.options, selectedVariantId);
|
||||
if (variant) {
|
||||
const variantColors = variant[colorMode] || variant.dark || variant.light || {};
|
||||
customThemeData = mergeColors(baseColors, variantColors);
|
||||
|
||||
if (themeData.variants.type === "multi" && themeData.variants.flavors && themeData.variants.accents) {
|
||||
const defaults = themeData.variants.defaults || {};
|
||||
const modeDefaults = defaults[colorMode] || defaults.dark || {};
|
||||
const stored = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, modeDefaults) : modeDefaults;
|
||||
var flavorId = stored.flavor || modeDefaults.flavor || "";
|
||||
const accentId = stored.accent || modeDefaults.accent || "";
|
||||
var flavor = findVariant(themeData.variants.flavors, flavorId);
|
||||
if (flavor) {
|
||||
const hasCurrentModeColors = flavor[colorMode] && (flavor[colorMode].primary || flavor[colorMode].surface);
|
||||
if (!hasCurrentModeColors) {
|
||||
flavorId = modeDefaults.flavor || "";
|
||||
flavor = findVariant(themeData.variants.flavors, flavorId);
|
||||
}
|
||||
}
|
||||
const accent = findAccent(themeData.variants.accents, accentId);
|
||||
if (flavor) {
|
||||
const flavorColors = flavor[colorMode] || flavor.dark || flavor.light || {};
|
||||
baseColors = mergeColors(baseColors, flavorColors);
|
||||
}
|
||||
if (accent && flavor) {
|
||||
const accentColors = accent[flavor.id] || {};
|
||||
baseColors = mergeColors(baseColors, accentColors);
|
||||
}
|
||||
customThemeData = baseColors;
|
||||
generateSystemThemesFromCurrentTheme();
|
||||
return;
|
||||
}
|
||||
|
||||
if (themeData.variants.options && themeData.variants.options.length > 0) {
|
||||
const selectedVariantId = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeVariant(themeId, themeData.variants.default) : themeData.variants.default;
|
||||
const variant = findVariant(themeData.variants.options, selectedVariantId);
|
||||
if (variant) {
|
||||
const variantColors = variant[colorMode] || variant.dark || variant.light || {};
|
||||
customThemeData = mergeColors(baseColors, variantColors);
|
||||
generateSystemThemesFromCurrentTheme();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customThemeData = baseColors;
|
||||
@@ -641,6 +628,16 @@ Singleton {
|
||||
return options[0] || null;
|
||||
}
|
||||
|
||||
function findAccent(accents, accentId) {
|
||||
if (!accentId || !accents)
|
||||
return null;
|
||||
for (var i = 0; i < accents.length; i++) {
|
||||
if (accents[i].id === accentId)
|
||||
return accents[i];
|
||||
}
|
||||
return accents[0] || null;
|
||||
}
|
||||
|
||||
function mergeColors(base, overlay) {
|
||||
var result = JSON.parse(JSON.stringify(base));
|
||||
for (var key in overlay) {
|
||||
@@ -954,13 +951,38 @@ Singleton {
|
||||
darkTheme = customThemeRawData.dark || customThemeRawData.light;
|
||||
lightTheme = customThemeRawData.light || customThemeRawData.dark;
|
||||
|
||||
if (customThemeRawData.variants && customThemeRawData.variants.options) {
|
||||
if (customThemeRawData.variants) {
|
||||
const themeId = customThemeRawData.id || "";
|
||||
const selectedVariantId = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeVariant(themeId, customThemeRawData.variants.default) : customThemeRawData.variants.default;
|
||||
const variant = findVariant(customThemeRawData.variants.options, selectedVariantId);
|
||||
if (variant) {
|
||||
darkTheme = mergeColors(darkTheme, variant.dark || {});
|
||||
lightTheme = mergeColors(lightTheme, variant.light || {});
|
||||
|
||||
if (customThemeRawData.variants.type === "multi" && customThemeRawData.variants.flavors && customThemeRawData.variants.accents) {
|
||||
const defaults = customThemeRawData.variants.defaults || {};
|
||||
const darkDefaults = defaults.dark || {};
|
||||
const lightDefaults = defaults.light || defaults.dark || {};
|
||||
const storedDark = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, darkDefaults) : darkDefaults;
|
||||
const storedLight = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, lightDefaults) : lightDefaults;
|
||||
const darkFlavorId = storedDark.flavor || darkDefaults.flavor || "";
|
||||
const lightFlavorId = storedLight.flavor || lightDefaults.flavor || "";
|
||||
const accentId = storedDark.accent || darkDefaults.accent || "";
|
||||
const darkFlavor = findVariant(customThemeRawData.variants.flavors, darkFlavorId);
|
||||
const lightFlavor = findVariant(customThemeRawData.variants.flavors, lightFlavorId);
|
||||
const accent = findAccent(customThemeRawData.variants.accents, accentId);
|
||||
if (darkFlavor) {
|
||||
darkTheme = mergeColors(darkTheme, darkFlavor.dark || {});
|
||||
if (accent)
|
||||
darkTheme = mergeColors(darkTheme, accent[darkFlavor.id] || {});
|
||||
}
|
||||
if (lightFlavor) {
|
||||
lightTheme = mergeColors(lightTheme, lightFlavor.light || {});
|
||||
if (accent)
|
||||
lightTheme = mergeColors(lightTheme, accent[lightFlavor.id] || {});
|
||||
}
|
||||
} else if (customThemeRawData.variants.options) {
|
||||
const selectedVariantId = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeVariant(themeId, customThemeRawData.variants.default) : customThemeRawData.variants.default;
|
||||
const variant = findVariant(customThemeRawData.variants.options, selectedVariantId);
|
||||
if (variant) {
|
||||
darkTheme = mergeColors(darkTheme, variant.dark || {});
|
||||
lightTheme = mergeColors(lightTheme, variant.light || {});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -78,9 +78,7 @@ FloatingWindow {
|
||||
closingModal();
|
||||
} else {
|
||||
Qt.callLater(() => {
|
||||
if (contentFocusScope) {
|
||||
contentFocusScope.forceActiveFocus();
|
||||
}
|
||||
sidebar.focusSearch();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -141,19 +139,6 @@ FloatingWindow {
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_Down || (event.key === Qt.Key_Tab && !event.modifiers)) {
|
||||
sidebar.navigateNext();
|
||||
event.accepted = true;
|
||||
return;
|
||||
}
|
||||
if (event.key === Qt.Key_Up || event.key === Qt.Key_Backtab || (event.key === Qt.Key_Tab && event.modifiers & Qt.ShiftModifier)) {
|
||||
sidebar.navigatePrevious();
|
||||
event.accepted = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Modals.Settings
|
||||
import qs.Services
|
||||
@@ -16,6 +17,49 @@ Rectangle {
|
||||
property var parentModal: null
|
||||
property var expandedCategories: ({})
|
||||
property var autoExpandedCategories: ({})
|
||||
property bool searchActive: searchField.text.length > 0
|
||||
property int searchSelectedIndex: 0
|
||||
property int keyboardHighlightIndex: -1
|
||||
|
||||
function focusSearch() {
|
||||
searchField.forceActiveFocus();
|
||||
}
|
||||
|
||||
function highlightNext() {
|
||||
var flatItems = getFlatNavigableItems();
|
||||
if (flatItems.length === 0)
|
||||
return;
|
||||
var currentPos = flatItems.findIndex(item => item.tabIndex === keyboardHighlightIndex);
|
||||
if (currentPos === -1) {
|
||||
currentPos = flatItems.findIndex(item => item.tabIndex === currentIndex);
|
||||
}
|
||||
var nextPos = (currentPos + 1) % flatItems.length;
|
||||
keyboardHighlightIndex = flatItems[nextPos].tabIndex;
|
||||
autoExpandForTab(keyboardHighlightIndex);
|
||||
}
|
||||
|
||||
function highlightPrevious() {
|
||||
var flatItems = getFlatNavigableItems();
|
||||
if (flatItems.length === 0)
|
||||
return;
|
||||
var currentPos = flatItems.findIndex(item => item.tabIndex === keyboardHighlightIndex);
|
||||
if (currentPos === -1) {
|
||||
currentPos = flatItems.findIndex(item => item.tabIndex === currentIndex);
|
||||
}
|
||||
var prevPos = (currentPos - 1 + flatItems.length) % flatItems.length;
|
||||
keyboardHighlightIndex = flatItems[prevPos].tabIndex;
|
||||
autoExpandForTab(keyboardHighlightIndex);
|
||||
}
|
||||
|
||||
function selectHighlighted() {
|
||||
if (keyboardHighlightIndex < 0)
|
||||
return;
|
||||
var oldIndex = currentIndex;
|
||||
currentIndex = keyboardHighlightIndex;
|
||||
autoCollapseIfNeeded(oldIndex, currentIndex);
|
||||
keyboardHighlightIndex = -1;
|
||||
Qt.callLater(searchField.forceActiveFocus);
|
||||
}
|
||||
|
||||
readonly property var categoryStructure: [
|
||||
{
|
||||
@@ -437,6 +481,29 @@ Rectangle {
|
||||
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
||||
radius: Theme.cornerRadius
|
||||
|
||||
function selectSearchResult(result) {
|
||||
if (!result)
|
||||
return;
|
||||
if (result.section) {
|
||||
SettingsSearchService.navigateToSection(result.section);
|
||||
}
|
||||
var oldIndex = root.currentIndex;
|
||||
root.currentIndex = result.tabIndex;
|
||||
autoCollapseIfNeeded(oldIndex, result.tabIndex);
|
||||
autoExpandForTab(result.tabIndex);
|
||||
searchField.text = "";
|
||||
SettingsSearchService.clear();
|
||||
searchSelectedIndex = 0;
|
||||
keyboardHighlightIndex = -1;
|
||||
Qt.callLater(searchField.forceActiveFocus);
|
||||
}
|
||||
|
||||
function navigateSearchResults(delta) {
|
||||
if (SettingsSearchService.results.length === 0)
|
||||
return;
|
||||
searchSelectedIndex = Math.max(0, Math.min(searchSelectedIndex + delta, SettingsSearchService.results.length - 1));
|
||||
}
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
@@ -465,7 +532,184 @@ Rectangle {
|
||||
|
||||
Item {
|
||||
width: parent.width - parent.leftPadding - parent.rightPadding
|
||||
height: Theme.spacingM
|
||||
height: Theme.spacingS
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
id: searchField
|
||||
width: parent.width - parent.leftPadding - parent.rightPadding
|
||||
placeholderText: I18n.tr("Search...")
|
||||
backgroundColor: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency)
|
||||
normalBorderColor: Theme.outlineMedium
|
||||
focusedBorderColor: Theme.primary
|
||||
leftIconName: "search"
|
||||
leftIconSize: Theme.iconSize - 4
|
||||
showClearButton: text.length > 0
|
||||
onTextChanged: {
|
||||
SettingsSearchService.search(text);
|
||||
root.searchSelectedIndex = 0;
|
||||
}
|
||||
keyForwardTargets: [keyHandler]
|
||||
|
||||
Item {
|
||||
id: keyHandler
|
||||
function navNext() {
|
||||
if (root.searchActive) {
|
||||
root.navigateSearchResults(1);
|
||||
} else {
|
||||
root.highlightNext();
|
||||
}
|
||||
}
|
||||
function navPrev() {
|
||||
if (root.searchActive) {
|
||||
root.navigateSearchResults(-1);
|
||||
} else {
|
||||
root.highlightPrevious();
|
||||
}
|
||||
}
|
||||
function navSelect() {
|
||||
if (root.searchActive && SettingsSearchService.results.length > 0) {
|
||||
root.selectSearchResult(SettingsSearchService.results[root.searchSelectedIndex]);
|
||||
} else if (root.keyboardHighlightIndex >= 0) {
|
||||
root.selectHighlighted();
|
||||
}
|
||||
}
|
||||
Keys.onDownPressed: event => {
|
||||
navNext();
|
||||
event.accepted = true;
|
||||
}
|
||||
Keys.onUpPressed: event => {
|
||||
navPrev();
|
||||
event.accepted = true;
|
||||
}
|
||||
Keys.onTabPressed: event => {
|
||||
navNext();
|
||||
event.accepted = true;
|
||||
}
|
||||
Keys.onBacktabPressed: event => {
|
||||
navPrev();
|
||||
event.accepted = true;
|
||||
}
|
||||
Keys.onReturnPressed: event => {
|
||||
navSelect();
|
||||
event.accepted = true;
|
||||
}
|
||||
Keys.onEscapePressed: event => {
|
||||
if (root.searchActive) {
|
||||
searchField.text = "";
|
||||
SettingsSearchService.clear();
|
||||
} else {
|
||||
root.keyboardHighlightIndex = -1;
|
||||
}
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: searchResultsColumn
|
||||
width: parent.width - parent.leftPadding - parent.rightPadding
|
||||
spacing: 2
|
||||
visible: root.searchActive
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: Theme.spacingS
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: ScriptModel {
|
||||
values: SettingsSearchService.results
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: resultDelegate
|
||||
required property int index
|
||||
required property var modelData
|
||||
|
||||
width: searchResultsColumn.width
|
||||
height: resultContent.height + Theme.spacingM * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (root.searchSelectedIndex === index)
|
||||
return Theme.primary;
|
||||
if (resultMouseArea.containsMouse)
|
||||
return Theme.surfaceHover;
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
Row {
|
||||
id: resultContent
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: resultDelegate.modelData.icon || "settings"
|
||||
size: Theme.iconSize - 2
|
||||
color: root.searchSelectedIndex === resultDelegate.index ? Theme.primaryText : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: resultDelegate.modelData.label
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: root.searchSelectedIndex === resultDelegate.index ? Theme.primaryText : Theme.surfaceText
|
||||
width: parent.width
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: resultDelegate.modelData.category
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: root.searchSelectedIndex === resultDelegate.index ? Theme.withAlpha(Theme.primaryText, 0.7) : Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: resultMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.selectSearchResult(resultDelegate.modelData)
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: I18n.tr("No matches")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
visible: searchField.text.length > 0 && SettingsSearchService.results.length === 0
|
||||
topPadding: Theme.spacingM
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - parent.leftPadding - parent.rightPadding
|
||||
height: Theme.spacingS
|
||||
visible: !root.searchActive
|
||||
}
|
||||
|
||||
Repeater {
|
||||
@@ -477,7 +721,7 @@ Rectangle {
|
||||
required property var modelData
|
||||
|
||||
width: parent.width - parent.leftPadding - parent.rightPadding
|
||||
visible: root.isCategoryVisible(modelData)
|
||||
visible: !root.searchActive && root.isCategoryVisible(modelData)
|
||||
spacing: 2
|
||||
|
||||
Rectangle {
|
||||
@@ -500,11 +744,16 @@ Rectangle {
|
||||
height: 40
|
||||
radius: Theme.cornerRadius
|
||||
visible: categoryDelegate.modelData.separator !== true
|
||||
|
||||
readonly property bool hasTab: categoryDelegate.modelData.tabIndex !== undefined && !categoryDelegate.modelData.children
|
||||
readonly property bool isActive: hasTab && root.currentIndex === categoryDelegate.modelData.tabIndex
|
||||
readonly property bool isHighlighted: hasTab && root.keyboardHighlightIndex === categoryDelegate.modelData.tabIndex
|
||||
|
||||
color: {
|
||||
var hasTab = categoryDelegate.modelData.tabIndex !== undefined && !categoryDelegate.modelData.children;
|
||||
var isActive = hasTab && root.currentIndex === categoryDelegate.modelData.tabIndex;
|
||||
if (isActive)
|
||||
return Theme.primary;
|
||||
if (isHighlighted)
|
||||
return Theme.primaryHover;
|
||||
if (categoryMouseArea.containsMouse)
|
||||
return Theme.surfaceHover;
|
||||
return "transparent";
|
||||
@@ -521,28 +770,15 @@ Rectangle {
|
||||
DankIcon {
|
||||
name: categoryDelegate.modelData.icon || ""
|
||||
size: Theme.iconSize - 2
|
||||
color: {
|
||||
var hasTab = categoryDelegate.modelData.tabIndex !== undefined && !categoryDelegate.modelData.children;
|
||||
var isActive = hasTab && root.currentIndex === categoryDelegate.modelData.tabIndex;
|
||||
return isActive ? Theme.primaryText : Theme.surfaceText;
|
||||
}
|
||||
color: categoryRow.isActive ? Theme.primaryText : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: categoryDelegate.modelData.text || ""
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: {
|
||||
var hasTab = categoryDelegate.modelData.tabIndex !== undefined && !categoryDelegate.modelData.children;
|
||||
var isActive = hasTab && root.currentIndex === categoryDelegate.modelData.tabIndex;
|
||||
var childActive = root.isChildActive(categoryDelegate.modelData);
|
||||
return (isActive || childActive) ? Font.Medium : Font.Normal;
|
||||
}
|
||||
color: {
|
||||
var hasTab = categoryDelegate.modelData.tabIndex !== undefined && !categoryDelegate.modelData.children;
|
||||
var isActive = hasTab && root.currentIndex === categoryDelegate.modelData.tabIndex;
|
||||
return isActive ? Theme.primaryText : Theme.surfaceText;
|
||||
}
|
||||
font.weight: (categoryRow.isActive || root.isChildActive(categoryDelegate.modelData)) ? Font.Medium : Font.Normal
|
||||
color: categoryRow.isActive ? Theme.primaryText : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM - (categoryDelegate.modelData.children ? expandIcon.width + Theme.spacingS : 0)
|
||||
elide: Text.ElideRight
|
||||
@@ -564,11 +800,13 @@ Rectangle {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.keyboardHighlightIndex = -1;
|
||||
if (categoryDelegate.modelData.children) {
|
||||
root.toggleCategory(categoryDelegate.modelData.id);
|
||||
} else if (categoryDelegate.modelData.tabIndex !== undefined) {
|
||||
root.currentIndex = categoryDelegate.modelData.tabIndex;
|
||||
}
|
||||
Qt.callLater(searchField.forceActiveFocus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -595,14 +833,18 @@ Rectangle {
|
||||
required property int index
|
||||
required property var modelData
|
||||
|
||||
readonly property bool isActive: root.currentIndex === modelData.tabIndex
|
||||
readonly property bool isHighlighted: root.keyboardHighlightIndex === modelData.tabIndex
|
||||
|
||||
width: childrenColumn.width
|
||||
height: 36
|
||||
radius: Theme.cornerRadius
|
||||
visible: root.isItemVisible(modelData)
|
||||
color: {
|
||||
var isActive = root.currentIndex === modelData.tabIndex;
|
||||
if (isActive)
|
||||
return Theme.primary;
|
||||
if (isHighlighted)
|
||||
return Theme.primaryHover;
|
||||
if (childMouseArea.containsMouse)
|
||||
return Theme.surfaceHover;
|
||||
return "transparent";
|
||||
@@ -617,21 +859,15 @@ Rectangle {
|
||||
DankIcon {
|
||||
name: childDelegate.modelData.icon || ""
|
||||
size: Theme.iconSize - 4
|
||||
color: {
|
||||
var isActive = root.currentIndex === childDelegate.modelData.tabIndex;
|
||||
return isActive ? Theme.primaryText : Theme.surfaceVariantText;
|
||||
}
|
||||
color: childDelegate.isActive ? Theme.primaryText : Theme.surfaceVariantText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: childDelegate.modelData.text || ""
|
||||
font.pixelSize: Theme.fontSizeSmall + 1
|
||||
font.weight: root.currentIndex === childDelegate.modelData.tabIndex ? Font.Medium : Font.Normal
|
||||
color: {
|
||||
var isActive = root.currentIndex === childDelegate.modelData.tabIndex;
|
||||
return isActive ? Theme.primaryText : Theme.surfaceText;
|
||||
}
|
||||
font.weight: childDelegate.isActive ? Font.Medium : Font.Normal
|
||||
color: childDelegate.isActive ? Theme.primaryText : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
@@ -642,7 +878,9 @@ Rectangle {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.keyboardHighlightIndex = -1;
|
||||
root.currentIndex = childDelegate.modelData.tabIndex;
|
||||
Qt.callLater(searchField.forceActiveFocus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,7 @@ BasePill {
|
||||
service: DMSNetworkService
|
||||
}
|
||||
|
||||
property var popoutTarget: null
|
||||
property var barConfig: null
|
||||
property bool isHovered: clickArea.containsMouse
|
||||
property real barSpacing: 4
|
||||
property bool isAutoHideBar: false
|
||||
|
||||
readonly property real minTooltipY: {
|
||||
@@ -45,7 +42,7 @@ BasePill {
|
||||
|
||||
name: DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off"
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: DMSNetworkService.connected ? Theme.primary : Theme.surfaceText
|
||||
color: DMSNetworkService.connected ? Theme.primary : Theme.widgetIconColor
|
||||
opacity: DMSNetworkService.isBusy ? 0.5 : 1.0
|
||||
anchors.centerIn: parent
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -200,6 +200,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
@@ -297,6 +297,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
@@ -304,6 +305,7 @@ Item {
|
||||
SettingsCard {
|
||||
iconName: "dashboard"
|
||||
title: I18n.tr("Bar Configurations")
|
||||
settingKey: "barConfigurations"
|
||||
|
||||
RowLayout {
|
||||
width: parent.width
|
||||
@@ -491,6 +493,7 @@ Item {
|
||||
SettingsCard {
|
||||
iconName: "display_settings"
|
||||
title: I18n.tr("Display Assignment")
|
||||
settingKey: "barDisplay"
|
||||
visible: selectedBarConfig?.enabled
|
||||
|
||||
StyledText {
|
||||
@@ -594,6 +597,7 @@ Item {
|
||||
SettingsCard {
|
||||
iconName: "vertical_align_center"
|
||||
title: I18n.tr("Position")
|
||||
settingKey: "barPosition"
|
||||
visible: selectedBarConfig?.enabled
|
||||
|
||||
Item {
|
||||
@@ -654,6 +658,7 @@ Item {
|
||||
SettingsCard {
|
||||
iconName: "visibility_off"
|
||||
title: I18n.tr("Visibility")
|
||||
settingKey: "barVisibility"
|
||||
visible: selectedBarConfig?.enabled
|
||||
|
||||
SettingsToggleRow {
|
||||
@@ -855,6 +860,7 @@ Item {
|
||||
SettingsCard {
|
||||
iconName: "space_bar"
|
||||
title: I18n.tr("Spacing")
|
||||
settingKey: "barSpacing"
|
||||
visible: selectedBarConfig?.enabled
|
||||
|
||||
SettingsSliderRow {
|
||||
@@ -974,6 +980,7 @@ Item {
|
||||
SettingsCard {
|
||||
iconName: "rounded_corner"
|
||||
title: I18n.tr("Corners & Background")
|
||||
settingKey: "barCorners"
|
||||
visible: selectedBarConfig?.enabled
|
||||
|
||||
SettingsToggleRow {
|
||||
@@ -1224,6 +1231,7 @@ Item {
|
||||
SettingsCard {
|
||||
iconName: "opacity"
|
||||
title: I18n.tr("Transparency")
|
||||
settingKey: "barTransparency"
|
||||
visible: selectedBarConfig?.enabled
|
||||
|
||||
SettingsSliderRow {
|
||||
|
||||
@@ -35,6 +35,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
@@ -28,6 +28,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -123,6 +123,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -15,6 +15,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
@@ -23,6 +24,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "swap_vert"
|
||||
title: I18n.tr("Dock Position")
|
||||
settingKey: "dockPosition"
|
||||
|
||||
SettingsButtonGroupRow {
|
||||
text: I18n.tr("Position")
|
||||
@@ -66,8 +68,11 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "dock_to_bottom"
|
||||
title: I18n.tr("Dock Visibility")
|
||||
settingKey: "dockVisibility"
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "showDock"
|
||||
tags: ["dock", "show", "display", "enable"]
|
||||
text: I18n.tr("Show Dock")
|
||||
description: I18n.tr("Display a dock with pinned and running applications")
|
||||
checked: SettingsData.showDock
|
||||
@@ -75,6 +80,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "dockAutoHide"
|
||||
tags: ["dock", "autohide", "hide", "hover"]
|
||||
text: I18n.tr("Auto-hide Dock")
|
||||
description: I18n.tr("Hide the dock when not in use and reveal it when hovering near the dock area")
|
||||
checked: SettingsData.dockAutoHide
|
||||
@@ -83,6 +90,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "dockOpenOnOverview"
|
||||
tags: ["dock", "overview", "niri"]
|
||||
text: I18n.tr("Show on Overview")
|
||||
description: I18n.tr("Always show the dock when niri's overview is open")
|
||||
checked: SettingsData.dockOpenOnOverview
|
||||
@@ -95,8 +104,11 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "apps"
|
||||
title: I18n.tr("Behavior")
|
||||
settingKey: "dockBehavior"
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "dockIsolateDisplays"
|
||||
tags: ["dock", "isolate", "monitor", "multi-monitor"]
|
||||
text: I18n.tr("Isolate Displays")
|
||||
description: I18n.tr("Only show windows from the current monitor on each dock")
|
||||
checked: SettingsData.dockIsolateDisplays
|
||||
@@ -104,6 +116,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "dockGroupByApp"
|
||||
tags: ["dock", "group", "windows", "app"]
|
||||
text: I18n.tr("Group by App")
|
||||
description: I18n.tr("Group multiple windows of the same app together with a window count indicator")
|
||||
checked: SettingsData.dockGroupByApp
|
||||
@@ -111,6 +125,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsButtonGroupRow {
|
||||
settingKey: "dockIndicatorStyle"
|
||||
tags: ["dock", "indicator", "style", "circle", "line"]
|
||||
text: I18n.tr("Indicator Style")
|
||||
model: ["Circle", "Line"]
|
||||
currentIndex: SettingsData.dockIndicatorStyle === "circle" ? 0 : 1
|
||||
@@ -126,8 +142,11 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "photo_size_select_large"
|
||||
title: I18n.tr("Sizing")
|
||||
settingKey: "dockSizing"
|
||||
|
||||
SettingsSliderRow {
|
||||
settingKey: "dockIconSize"
|
||||
tags: ["dock", "icon", "size", "scale"]
|
||||
text: I18n.tr("Icon Size")
|
||||
value: SettingsData.dockIconSize
|
||||
minimum: 24
|
||||
@@ -141,6 +160,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "space_bar"
|
||||
title: I18n.tr("Spacing")
|
||||
settingKey: "dockSpacing"
|
||||
|
||||
SettingsSliderRow {
|
||||
text: I18n.tr("Padding")
|
||||
@@ -174,6 +194,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "opacity"
|
||||
title: I18n.tr("Transparency")
|
||||
settingKey: "dockTransparency"
|
||||
|
||||
SettingsSliderRow {
|
||||
text: I18n.tr("Dock Transparency")
|
||||
@@ -190,6 +211,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "border_style"
|
||||
title: I18n.tr("Border")
|
||||
settingKey: "dockBorder"
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Border")
|
||||
|
||||
@@ -27,6 +27,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -25,6 +25,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
@@ -33,6 +34,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "apps"
|
||||
title: I18n.tr("Launcher Button Logo")
|
||||
settingKey: "launcherLogo"
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
@@ -248,6 +250,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsSliderRow {
|
||||
settingKey: "launcherLogoSizeOffset"
|
||||
tags: ["launcher", "logo", "size", "offset", "scale"]
|
||||
text: I18n.tr("Size Offset")
|
||||
minimum: -12
|
||||
maximum: 12
|
||||
@@ -265,6 +269,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsSliderRow {
|
||||
settingKey: "launcherLogoBrightness"
|
||||
tags: ["launcher", "logo", "brightness", "color"]
|
||||
text: I18n.tr("Brightness")
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
@@ -275,6 +281,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsSliderRow {
|
||||
settingKey: "launcherLogoContrast"
|
||||
tags: ["launcher", "logo", "contrast", "color"]
|
||||
text: I18n.tr("Contrast")
|
||||
minimum: 0
|
||||
maximum: 200
|
||||
@@ -285,6 +293,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "launcherLogoColorInvertOnMode"
|
||||
tags: ["launcher", "logo", "invert", "mode", "color"]
|
||||
text: I18n.tr("Invert on mode change")
|
||||
checked: SettingsData.launcherLogoColorInvertOnMode
|
||||
onToggled: checked => SettingsData.set("launcherLogoColorInvertOnMode", checked)
|
||||
@@ -297,6 +307,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "terminal"
|
||||
title: I18n.tr("Launch Prefix")
|
||||
settingKey: "launchPrefix"
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
@@ -318,8 +329,11 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "sort_by_alpha"
|
||||
title: I18n.tr("Sorting & Layout")
|
||||
settingKey: "launcherSorting"
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "sortAppsAlphabetically"
|
||||
tags: ["launcher", "sort", "alphabetically", "apps", "order"]
|
||||
text: I18n.tr("Sort Alphabetically")
|
||||
description: I18n.tr("When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.")
|
||||
checked: SettingsData.sortAppsAlphabetically
|
||||
@@ -327,6 +341,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsSliderRow {
|
||||
settingKey: "appLauncherGridColumns"
|
||||
tags: ["launcher", "grid", "columns", "layout"]
|
||||
text: I18n.tr("Grid Columns")
|
||||
description: I18n.tr("Adjust the number of columns in grid view mode.")
|
||||
minimum: 2
|
||||
@@ -344,6 +360,8 @@ Item {
|
||||
visible: CompositorService.isNiri
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "spotlightCloseNiriOverview"
|
||||
tags: ["launcher", "niri", "overview", "close", "launch"]
|
||||
text: I18n.tr("Close Overview on Launch")
|
||||
description: I18n.tr("Auto-close Niri overview when launching apps.")
|
||||
checked: SettingsData.spotlightCloseNiriOverview
|
||||
@@ -351,6 +369,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "niriOverviewOverlayEnabled"
|
||||
tags: ["launcher", "niri", "overview", "overlay", "enable"]
|
||||
text: I18n.tr("Enable Overview Overlay")
|
||||
description: I18n.tr("Show launcher overlay when typing in Niri overview. Disable to use another launcher.")
|
||||
checked: SettingsData.niriOverviewOverlayEnabled
|
||||
@@ -363,6 +383,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "history"
|
||||
title: I18n.tr("Recently Used Apps")
|
||||
settingKey: "recentApps"
|
||||
|
||||
property var rankedAppsModel: {
|
||||
var ranking = AppUsageHistoryData.appUsageRanking;
|
||||
|
||||
@@ -16,6 +16,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
@@ -24,38 +25,51 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "lock"
|
||||
title: I18n.tr("Lock Screen layout")
|
||||
settingKey: "lockLayout"
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "lockScreenShowPowerActions"
|
||||
tags: ["lock", "screen", "power", "actions", "shutdown", "reboot"]
|
||||
text: I18n.tr("Show Power Actions", "Enable power action icon on the lock screen window")
|
||||
checked: SettingsData.lockScreenShowPowerActions
|
||||
onToggled: checked => SettingsData.set("lockScreenShowPowerActions", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "lockScreenShowSystemIcons"
|
||||
tags: ["lock", "screen", "system", "icons", "status"]
|
||||
text: I18n.tr("Show System Icons", "Enable system status icons on the lock screen window")
|
||||
checked: SettingsData.lockScreenShowSystemIcons
|
||||
onToggled: checked => SettingsData.set("lockScreenShowSystemIcons", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "lockScreenShowTime"
|
||||
tags: ["lock", "screen", "time", "clock", "display"]
|
||||
text: I18n.tr("Show System Time", "Enable system time display on the lock screen window")
|
||||
checked: SettingsData.lockScreenShowTime
|
||||
onToggled: checked => SettingsData.set("lockScreenShowTime", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "lockScreenShowDate"
|
||||
tags: ["lock", "screen", "date", "calendar", "display"]
|
||||
text: I18n.tr("Show System Date", "Enable system date display on the lock screen window")
|
||||
checked: SettingsData.lockScreenShowDate
|
||||
onToggled: checked => SettingsData.set("lockScreenShowDate", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "lockScreenShowProfileImage"
|
||||
tags: ["lock", "screen", "profile", "image", "avatar", "picture"]
|
||||
text: I18n.tr("Show Profile Image", "Enable profile image display on the lock screen window")
|
||||
checked: SettingsData.lockScreenShowProfileImage
|
||||
onToggled: checked => SettingsData.set("lockScreenShowProfileImage", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "lockScreenShowPasswordField"
|
||||
tags: ["lock", "screen", "password", "field", "input", "visible"]
|
||||
text: I18n.tr("Show Password Field", "Enable password field display on the lock screen window")
|
||||
description: I18n.tr("If the field is hidden, it will appear as soon as a key is pressed.")
|
||||
checked: SettingsData.lockScreenShowPasswordField
|
||||
@@ -67,6 +81,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "lock"
|
||||
title: I18n.tr("Lock Screen behaviour")
|
||||
settingKey: "lockBehavior"
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("loginctl not available - lock integration requires DMS socket connection")
|
||||
@@ -78,6 +93,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "loginctlLockIntegration"
|
||||
tags: ["lock", "screen", "loginctl", "dbus", "integration", "external"]
|
||||
text: I18n.tr("Enable loginctl lock integration")
|
||||
description: I18n.tr("Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen")
|
||||
checked: SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration
|
||||
@@ -90,6 +107,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "lockBeforeSuspend"
|
||||
tags: ["lock", "screen", "suspend", "sleep", "automatic"]
|
||||
text: I18n.tr("Lock before suspend")
|
||||
description: I18n.tr("Automatically lock the screen when the system prepares to suspend")
|
||||
checked: SettingsData.lockBeforeSuspend
|
||||
@@ -98,6 +117,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "enableFprint"
|
||||
tags: ["lock", "screen", "fingerprint", "authentication", "biometric", "fprint"]
|
||||
text: I18n.tr("Enable fingerprint authentication")
|
||||
description: I18n.tr("Use fingerprint reader for lock screen authentication (requires enrolled fingerprints)")
|
||||
checked: SettingsData.enableFprint
|
||||
@@ -110,6 +131,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "monitor"
|
||||
title: I18n.tr("Lock Screen Display")
|
||||
settingKey: "lockDisplay"
|
||||
visible: Quickshell.screens.length > 1
|
||||
|
||||
StyledText {
|
||||
@@ -122,6 +144,8 @@ Item {
|
||||
|
||||
SettingsDropdownRow {
|
||||
id: lockScreenMonitorDropdown
|
||||
settingKey: "lockScreenActiveMonitor"
|
||||
tags: ["lock", "screen", "monitor", "display", "active"]
|
||||
text: I18n.tr("Active Lock Screen Monitor")
|
||||
options: {
|
||||
var opts = [I18n.tr("All Monitors")];
|
||||
|
||||
@@ -14,6 +14,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
@@ -22,6 +23,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "music_note"
|
||||
title: I18n.tr("Media Player Settings")
|
||||
settingKey: "mediaPlayer"
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Wave Progress Bars")
|
||||
|
||||
@@ -51,6 +51,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
|
||||
width: Math.min(600, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -81,6 +81,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
@@ -89,8 +90,11 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "notifications"
|
||||
title: I18n.tr("Notification Popups")
|
||||
settingKey: "notificationPopups"
|
||||
|
||||
SettingsDropdownRow {
|
||||
settingKey: "notificationPopupPosition"
|
||||
tags: ["notification", "popup", "position", "screen", "location"]
|
||||
text: I18n.tr("Popup Position")
|
||||
description: I18n.tr("Choose where notification popups appear on screen")
|
||||
currentValue: {
|
||||
@@ -133,6 +137,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "notificationOverlayEnabled"
|
||||
tags: ["notification", "overlay", "fullscreen", "priority"]
|
||||
text: I18n.tr("Notification Overlay")
|
||||
description: I18n.tr("Display all priorities over fullscreen apps")
|
||||
checked: SettingsData.notificationOverlayEnabled
|
||||
@@ -144,8 +150,11 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "notifications_off"
|
||||
title: I18n.tr("Do Not Disturb")
|
||||
settingKey: "doNotDisturb"
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "doNotDisturb"
|
||||
tags: ["notification", "dnd", "mute", "silent", "suppress"]
|
||||
text: I18n.tr("Enable Do Not Disturb")
|
||||
description: I18n.tr("Suppress notification popups while enabled")
|
||||
checked: SessionData.doNotDisturb
|
||||
@@ -157,8 +166,11 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "timer"
|
||||
title: I18n.tr("Notification Timeouts")
|
||||
settingKey: "notificationTimeouts"
|
||||
|
||||
SettingsDropdownRow {
|
||||
settingKey: "notificationTimeoutLow"
|
||||
tags: ["notification", "timeout", "low", "priority", "duration"]
|
||||
text: I18n.tr("Low Priority")
|
||||
description: I18n.tr("Timeout for low priority notifications")
|
||||
currentValue: root.getTimeoutText(SettingsData.notificationTimeoutLow)
|
||||
@@ -174,6 +186,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsDropdownRow {
|
||||
settingKey: "notificationTimeoutNormal"
|
||||
tags: ["notification", "timeout", "normal", "priority", "duration"]
|
||||
text: I18n.tr("Normal Priority")
|
||||
description: I18n.tr("Timeout for normal priority notifications")
|
||||
currentValue: root.getTimeoutText(SettingsData.notificationTimeoutNormal)
|
||||
@@ -189,6 +203,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsDropdownRow {
|
||||
settingKey: "notificationTimeoutCritical"
|
||||
tags: ["notification", "timeout", "critical", "priority", "duration"]
|
||||
text: I18n.tr("Critical Priority")
|
||||
description: I18n.tr("Timeout for critical priority notifications")
|
||||
currentValue: root.getTimeoutText(SettingsData.notificationTimeoutCritical)
|
||||
|
||||
@@ -14,6 +14,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
@@ -22,6 +23,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "tune"
|
||||
title: I18n.tr("On-screen Displays")
|
||||
settingKey: "osd"
|
||||
|
||||
SettingsDropdownRow {
|
||||
text: I18n.tr("OSD Position")
|
||||
|
||||
@@ -27,6 +27,7 @@ FocusScope {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -23,6 +23,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
@@ -31,6 +32,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "schedule"
|
||||
title: I18n.tr("Idle Settings")
|
||||
settingKey: "idleSettings"
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
@@ -62,6 +64,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "fadeToLockEnabled"
|
||||
tags: ["fade", "lock", "screen", "idle", "grace period"]
|
||||
text: I18n.tr("Fade to lock screen")
|
||||
description: I18n.tr("Gradually fade the screen before locking with a configurable grace period")
|
||||
checked: SettingsData.fadeToLockEnabled
|
||||
@@ -69,6 +73,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "lockBeforeSuspend"
|
||||
tags: ["lock", "suspend", "sleep", "security"]
|
||||
text: I18n.tr("Lock before suspend")
|
||||
description: I18n.tr("Automatically lock the screen when the system prepares to suspend")
|
||||
checked: SettingsData.lockBeforeSuspend
|
||||
@@ -78,6 +84,8 @@ Item {
|
||||
|
||||
SettingsDropdownRow {
|
||||
id: fadeGracePeriodDropdown
|
||||
settingKey: "fadeToLockGracePeriod"
|
||||
tags: ["fade", "grace", "period", "timeout", "lock"]
|
||||
property var periodOptions: ["1 second", "2 seconds", "3 seconds", "4 seconds", "5 seconds", "10 seconds", "15 seconds", "20 seconds", "30 seconds"]
|
||||
property var periodValues: [1, 2, 3, 4, 5, 10, 15, 20, 30]
|
||||
|
||||
@@ -101,6 +109,8 @@ Item {
|
||||
}
|
||||
SettingsDropdownRow {
|
||||
id: powerProfileDropdown
|
||||
settingKey: "powerProfile"
|
||||
tags: ["power", "profile", "performance", "balanced", "saver", "battery"]
|
||||
property var profileOptions: [I18n.tr("Don't Change"), Theme.getPowerProfileLabel(0), Theme.getPowerProfileLabel(1), Theme.getPowerProfileLabel(2)]
|
||||
property var profileValues: ["", "0", "1", "2"]
|
||||
|
||||
@@ -146,6 +156,8 @@ Item {
|
||||
|
||||
SettingsDropdownRow {
|
||||
id: lockDropdown
|
||||
settingKey: "lockTimeout"
|
||||
tags: ["lock", "timeout", "idle", "automatic", "security"]
|
||||
text: I18n.tr("Automatically lock after")
|
||||
options: root.timeoutOptions
|
||||
|
||||
@@ -177,6 +189,8 @@ Item {
|
||||
|
||||
SettingsDropdownRow {
|
||||
id: monitorDropdown
|
||||
settingKey: "monitorTimeout"
|
||||
tags: ["monitor", "display", "screen", "timeout", "off", "idle"]
|
||||
text: I18n.tr("Turn off monitors after")
|
||||
options: root.timeoutOptions
|
||||
|
||||
@@ -208,6 +222,8 @@ Item {
|
||||
|
||||
SettingsDropdownRow {
|
||||
id: suspendDropdown
|
||||
settingKey: "suspendTimeout"
|
||||
tags: ["suspend", "sleep", "timeout", "idle", "system"]
|
||||
text: I18n.tr("Suspend system after")
|
||||
options: root.timeoutOptions
|
||||
|
||||
@@ -294,6 +310,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "tune"
|
||||
title: I18n.tr("Power Menu Customization")
|
||||
settingKey: "powerMenu"
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Customize which actions appear in the power menu")
|
||||
@@ -304,6 +321,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "powerMenuGridLayout"
|
||||
tags: ["power", "menu", "grid", "layout", "list"]
|
||||
text: I18n.tr("Use Grid Layout")
|
||||
description: I18n.tr("Display power menu actions in a grid instead of a list")
|
||||
checked: SettingsData.powerMenuGridLayout
|
||||
@@ -312,6 +331,8 @@ Item {
|
||||
|
||||
SettingsDropdownRow {
|
||||
id: defaultActionDropdown
|
||||
settingKey: "powerMenuDefaultAction"
|
||||
tags: ["power", "menu", "default", "action", "reboot", "logout", "shutdown"]
|
||||
text: I18n.tr("Default selected action")
|
||||
options: ["Reboot", "Log Out", "Power Off", "Lock", "Suspend", "Restart DMS", "Hibernate"]
|
||||
property var actionValues: ["reboot", "logout", "poweroff", "lock", "suspend", "restart", "hibernate"]
|
||||
@@ -378,6 +399,8 @@ Item {
|
||||
|
||||
SettingsToggleRow {
|
||||
required property var modelData
|
||||
settingKey: "powerMenuAction_" + modelData.key
|
||||
tags: ["power", "menu", "action", "show", modelData.key]
|
||||
text: modelData.label
|
||||
description: modelData.desc || ""
|
||||
visible: !modelData.hibernate || SessionService.hibernateSupported
|
||||
@@ -400,8 +423,11 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "check_circle"
|
||||
title: I18n.tr("Power Action Confirmation")
|
||||
settingKey: "powerConfirmation"
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "powerActionConfirm"
|
||||
tags: ["power", "confirm", "hold", "button", "safety"]
|
||||
text: I18n.tr("Hold to Confirm Power Actions")
|
||||
description: I18n.tr("Require holding button/key to confirm power off, restart, suspend, hibernate and logout")
|
||||
checked: SettingsData.powerActionConfirm
|
||||
@@ -410,6 +436,8 @@ Item {
|
||||
|
||||
SettingsDropdownRow {
|
||||
id: holdDurationDropdown
|
||||
settingKey: "powerActionHoldDuration"
|
||||
tags: ["power", "hold", "duration", "confirm", "time"]
|
||||
property var durationOptions: ["250 ms", "500 ms", "750 ms", "1 second", "2 seconds", "3 seconds", "5 seconds", "10 seconds"]
|
||||
property var durationValues: [0.25, 0.5, 0.75, 1, 2, 3, 5, 10]
|
||||
|
||||
@@ -436,6 +464,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "developer_mode"
|
||||
title: I18n.tr("Custom Power Actions")
|
||||
settingKey: "customPowerActions"
|
||||
|
||||
Repeater {
|
||||
model: [
|
||||
@@ -508,10 +537,13 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "tune"
|
||||
title: I18n.tr("Advanced")
|
||||
settingKey: "powerAdvanced"
|
||||
collapsible: true
|
||||
expanded: false
|
||||
|
||||
SettingsSliderRow {
|
||||
settingKey: "batteryChargeLimit"
|
||||
tags: ["battery", "charge", "limit", "percentage", "power"]
|
||||
text: I18n.tr("Battery Charge Limit")
|
||||
description: I18n.tr("Note: this only changes the percentage, it does not actually limit charging.")
|
||||
value: SettingsData.batteryChargeLimit
|
||||
|
||||
@@ -70,6 +70,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
|
||||
width: Math.min(600, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -14,6 +14,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
@@ -22,6 +23,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "apps"
|
||||
title: I18n.tr("Running Apps Settings")
|
||||
settingKey: "runningApps"
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Running Apps Only In Current Workspace")
|
||||
|
||||
@@ -15,6 +15,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -24,6 +25,7 @@ Item {
|
||||
tab: "sounds"
|
||||
tags: ["sound", "audio", "notification", "volume"]
|
||||
title: I18n.tr("System Sounds")
|
||||
settingKey: "systemSounds"
|
||||
iconName: SettingsData.soundsEnabled ? "volume_up" : "volume_off"
|
||||
visible: AudioService.soundsAvailable
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
@@ -22,6 +23,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "refresh"
|
||||
title: I18n.tr("System Updater")
|
||||
settingKey: "systemUpdater"
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Hide Updater Widget", "When updater widget is used, then hide it if no update found")
|
||||
|
||||
@@ -391,12 +391,24 @@ FloatingWindow {
|
||||
property bool isFirstParty: modelData.firstParty || false
|
||||
property bool hasVariants: modelData.hasVariants || false
|
||||
property var variants: modelData.variants || null
|
||||
property string selectedVariantId: hasVariants && variants ? (variants.default || (variants.options[0]?.id ?? "")) : ""
|
||||
property string selectedVariantId: {
|
||||
if (!hasVariants || !variants)
|
||||
return "";
|
||||
if (variants.type === "multi") {
|
||||
const mode = Theme.isLightMode ? "light" : "dark";
|
||||
const defaults = variants.defaults?.[mode] || variants.defaults?.dark || {};
|
||||
return (defaults.flavor || "") + (defaults.accent ? "-" + defaults.accent : "");
|
||||
}
|
||||
return variants.default || (variants.options?.[0]?.id ?? "");
|
||||
}
|
||||
property string previewPath: {
|
||||
const baseDir = "/tmp/dankdots-plugin-registry/themes/" + (modelData.sourceDir || modelData.id);
|
||||
const mode = Theme.isLightMode ? "light" : "dark";
|
||||
if (hasVariants && selectedVariantId)
|
||||
if (hasVariants && selectedVariantId) {
|
||||
if (variants?.type === "multi")
|
||||
return baseDir + "/preview-" + selectedVariantId + ".svg";
|
||||
return baseDir + "/preview-" + selectedVariantId + "-" + mode + ".svg";
|
||||
}
|
||||
return baseDir + "/preview-" + mode + ".svg";
|
||||
}
|
||||
property bool hasPreview: previewImage.status === Image.Ready
|
||||
@@ -503,7 +515,11 @@ FloatingWindow {
|
||||
StyledText {
|
||||
id: variantsText
|
||||
anchors.centerIn: parent
|
||||
text: I18n.tr("%1 variants").arg(themeDelegate.variants?.options?.length ?? 0)
|
||||
text: {
|
||||
if (themeDelegate.variants?.type === "multi")
|
||||
return I18n.tr("%1 variants").arg(themeDelegate.variants?.accents?.length ?? 0);
|
||||
return I18n.tr("%1 variants").arg(themeDelegate.variants?.options?.length ?? 0);
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.secondary
|
||||
font.weight: Font.Medium
|
||||
@@ -533,7 +549,7 @@ FloatingWindow {
|
||||
Flow {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
visible: themeDelegate.hasVariants
|
||||
visible: themeDelegate.hasVariants && themeDelegate.variants?.type !== "multi"
|
||||
|
||||
Repeater {
|
||||
model: themeDelegate.variants?.options ?? []
|
||||
@@ -563,6 +579,36 @@ FloatingWindow {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Flow {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
visible: themeDelegate.hasVariants && themeDelegate.variants?.type === "multi"
|
||||
|
||||
Repeater {
|
||||
model: themeDelegate.variants?.accents ?? []
|
||||
|
||||
Rectangle {
|
||||
width: 18
|
||||
height: 18
|
||||
radius: 9
|
||||
color: modelData.color || Theme.primary
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
|
||||
DankTooltipV2 {
|
||||
id: accentTooltip
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: accentTooltip.show(modelData.name || modelData.id, parent, 0, 0, "top")
|
||||
onExited: accentTooltip.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
||||
@@ -45,6 +45,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -54,6 +55,7 @@ Item {
|
||||
tab: "theme"
|
||||
tags: ["color", "palette", "theme", "appearance"]
|
||||
title: I18n.tr("Theme Color")
|
||||
settingKey: "themeColor"
|
||||
iconName: "palette"
|
||||
|
||||
Column {
|
||||
@@ -76,8 +78,6 @@ Item {
|
||||
return I18n.tr("Current Theme: %1", "current theme label").arg(I18n.tr("Dynamic", "dynamic theme name"));
|
||||
if (Theme.currentThemeCategory === "registry" && registryThemeName)
|
||||
return I18n.tr("Current Theme: %1", "current theme label").arg(registryThemeName);
|
||||
if (Theme.currentThemeCategory === "catppuccin")
|
||||
return I18n.tr("Current Theme: %1", "current theme label").arg("Catppuccin " + Theme.getThemeColors(Theme.currentThemeName).name);
|
||||
return I18n.tr("Current Theme: %1", "current theme label").arg(Theme.getThemeColors(Theme.currentThemeName).name);
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
@@ -92,8 +92,6 @@ Item {
|
||||
return I18n.tr("Material colors generated from wallpaper", "dynamic theme description");
|
||||
if (Theme.currentThemeCategory === "registry")
|
||||
return I18n.tr("Color theme from DMS registry", "registry theme description");
|
||||
if (Theme.currentThemeCategory === "catppuccin")
|
||||
return I18n.tr("Soothing pastel theme based on Catppuccin", "catppuccin theme description");
|
||||
if (Theme.currentTheme === Theme.custom)
|
||||
return I18n.tr("Custom theme loaded from JSON file", "custom theme description");
|
||||
return I18n.tr("Material Design inspired color themes", "generic theme description");
|
||||
@@ -127,18 +125,16 @@ Item {
|
||||
property bool isRegistryTheme: Theme.currentThemeCategory === "registry"
|
||||
property int currentThemeIndex: {
|
||||
if (isRegistryTheme)
|
||||
return 4;
|
||||
if (Theme.currentTheme === Theme.dynamic)
|
||||
return 2;
|
||||
if (Theme.currentThemeName === "custom")
|
||||
return 3;
|
||||
if (Theme.currentThemeCategory === "catppuccin")
|
||||
if (Theme.currentTheme === Theme.dynamic)
|
||||
return 1;
|
||||
if (Theme.currentThemeName === "custom")
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
property int pendingThemeIndex: -1
|
||||
|
||||
model: DMSService.dmsAvailable ? ["Generic", "Catppuccin", "Auto", "Custom", "Registry"] : ["Generic", "Catppuccin", "Auto", "Custom"]
|
||||
model: DMSService.dmsAvailable ? ["Generic", "Auto", "Custom", "Browse"] : ["Generic", "Auto", "Custom"]
|
||||
currentIndex: currentThemeIndex
|
||||
selectionMode: "single"
|
||||
onSelectionChanged: (index, selected) => {
|
||||
@@ -154,9 +150,6 @@ Item {
|
||||
Theme.switchThemeCategory("generic", "blue");
|
||||
break;
|
||||
case 1:
|
||||
Theme.switchThemeCategory("catppuccin", "cat-mauve");
|
||||
break;
|
||||
case 2:
|
||||
if (ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
ToastService.showError(I18n.tr("matugen not found - install matugen package for dynamic theming", "matugen error"));
|
||||
else if (ToastService.wallpaperErrorStatus === "error")
|
||||
@@ -164,10 +157,10 @@ Item {
|
||||
else
|
||||
Theme.switchThemeCategory("dynamic", Theme.dynamic);
|
||||
break;
|
||||
case 3:
|
||||
case 2:
|
||||
Theme.switchThemeCategory("custom", "custom");
|
||||
break;
|
||||
case 4:
|
||||
case 3:
|
||||
Theme.switchThemeCategory("registry", "");
|
||||
break;
|
||||
}
|
||||
@@ -176,116 +169,66 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Flow {
|
||||
id: genericColorFlow
|
||||
spacing: Theme.spacingS
|
||||
Item {
|
||||
width: parent.width
|
||||
height: genericColorGrid.implicitHeight
|
||||
visible: Theme.currentThemeCategory === "generic" && Theme.currentTheme !== Theme.dynamic && Theme.currentThemeName !== "custom"
|
||||
property int dotSize: width < 300 ? 28 : 32
|
||||
|
||||
Repeater {
|
||||
model: ["blue", "purple", "green", "orange", "red", "cyan", "pink", "amber", "coral", "monochrome"]
|
||||
Grid {
|
||||
id: genericColorGrid
|
||||
property var colorList: ["blue", "purple", "green", "orange", "red", "cyan", "pink", "amber", "coral", "monochrome"]
|
||||
property int dotSize: parent.width < 300 ? 28 : 32
|
||||
columns: Math.ceil(colorList.length / 2)
|
||||
rowSpacing: Theme.spacingS
|
||||
columnSpacing: Theme.spacingS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Rectangle {
|
||||
required property string modelData
|
||||
property string themeName: modelData
|
||||
width: genericColorFlow.dotSize
|
||||
height: genericColorFlow.dotSize
|
||||
radius: width / 2
|
||||
color: Theme.getThemeColors(themeName).primary
|
||||
border.color: Theme.outline
|
||||
border.width: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 2 : 1
|
||||
scale: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 1.1 : 1
|
||||
Repeater {
|
||||
model: genericColorGrid.colorList
|
||||
|
||||
Rectangle {
|
||||
width: nameText.contentWidth + Theme.spacingS * 2
|
||||
height: nameText.contentHeight + Theme.spacingXS * 2
|
||||
color: Theme.surfaceContainer
|
||||
radius: Theme.cornerRadius
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingXS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: mouseArea.containsMouse
|
||||
required property string modelData
|
||||
property string themeName: modelData
|
||||
width: genericColorGrid.dotSize
|
||||
height: genericColorGrid.dotSize
|
||||
radius: width / 2
|
||||
color: Theme.getThemeColors(themeName).primary
|
||||
border.color: Theme.outline
|
||||
border.width: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 2 : 1
|
||||
scale: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 1.1 : 1
|
||||
|
||||
StyledText {
|
||||
id: nameText
|
||||
text: Theme.getThemeColors(parent.parent.themeName).name
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
Rectangle {
|
||||
width: nameText.contentWidth + Theme.spacingS * 2
|
||||
height: nameText.contentHeight + Theme.spacingXS * 2
|
||||
color: Theme.surfaceContainer
|
||||
radius: Theme.cornerRadius
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingXS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: mouseArea.containsMouse
|
||||
|
||||
StyledText {
|
||||
id: nameText
|
||||
text: Theme.getThemeColors(parent.parent.themeName).name
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: Theme.switchTheme(parent.themeName)
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: Theme.switchTheme(parent.themeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Flow {
|
||||
id: catColorFlow
|
||||
spacing: Theme.spacingS
|
||||
width: parent.width
|
||||
visible: Theme.currentThemeCategory === "catppuccin" && Theme.currentTheme !== Theme.dynamic && Theme.currentThemeName !== "custom"
|
||||
property int dotSize: width < 300 ? 28 : 32
|
||||
|
||||
Repeater {
|
||||
model: ["cat-rosewater", "cat-flamingo", "cat-pink", "cat-mauve", "cat-red", "cat-maroon", "cat-peach", "cat-yellow", "cat-green", "cat-teal", "cat-sky", "cat-sapphire", "cat-blue", "cat-lavender"]
|
||||
|
||||
Rectangle {
|
||||
required property string modelData
|
||||
property string themeName: modelData
|
||||
width: catColorFlow.dotSize
|
||||
height: catColorFlow.dotSize
|
||||
radius: width / 2
|
||||
color: Theme.getCatppuccinColor(themeName)
|
||||
border.color: Theme.outline
|
||||
border.width: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 2 : 1
|
||||
scale: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 1.1 : 1
|
||||
|
||||
Rectangle {
|
||||
width: nameTextCat.contentWidth + Theme.spacingS * 2
|
||||
height: nameTextCat.contentHeight + Theme.spacingXS * 2
|
||||
color: Theme.surfaceContainer
|
||||
radius: Theme.cornerRadius
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingXS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: mouseAreaCat.containsMouse
|
||||
|
||||
StyledText {
|
||||
id: nameTextCat
|
||||
text: Theme.getCatppuccinVariantName(parent.parent.themeName)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseAreaCat
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: Theme.switchTheme(parent.themeName)
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -582,7 +525,11 @@ Item {
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: themeCard.variants?.options?.length || 0
|
||||
text: {
|
||||
if (themeCard.variants?.type === "multi")
|
||||
return themeCard.variants?.accents?.length || 0;
|
||||
return themeCard.variants?.options?.length || 0;
|
||||
}
|
||||
font.pixelSize: themeGrid.cardWidth < 120 ? Theme.fontSizeSmall - 4 : Theme.fontSizeSmall - 2
|
||||
color: Theme.surface
|
||||
font.weight: Font.Bold
|
||||
@@ -653,10 +600,10 @@ Item {
|
||||
id: variantSelector
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
visible: activeThemeVariants !== null && activeThemeVariants.options && activeThemeVariants.options.length > 0
|
||||
visible: activeThemeId !== "" && activeThemeVariants !== null && (isMultiVariant || (activeThemeVariants.options && activeThemeVariants.options.length > 0))
|
||||
|
||||
property string activeThemeId: {
|
||||
if (Theme.currentThemeCategory !== "registry")
|
||||
if (Theme.currentThemeCategory !== "registry" || Theme.currentTheme !== "custom")
|
||||
return "";
|
||||
for (var i = 0; i < themeColorsTab.installedRegistryThemes.length; i++) {
|
||||
var t = themeColorsTab.installedRegistryThemes[i];
|
||||
@@ -675,6 +622,29 @@ Item {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
property bool isMultiVariant: activeThemeVariants?.type === "multi"
|
||||
property string colorMode: Theme.isLightMode ? "light" : "dark"
|
||||
property var multiDefaults: {
|
||||
if (!isMultiVariant || !activeThemeVariants?.defaults)
|
||||
return {};
|
||||
return activeThemeVariants.defaults[colorMode] || activeThemeVariants.defaults.dark || {};
|
||||
}
|
||||
property var storedMulti: activeThemeId ? SettingsData.getRegistryThemeMultiVariant(activeThemeId, multiDefaults) : multiDefaults
|
||||
property string selectedFlavor: storedMulti.flavor || multiDefaults.flavor || ""
|
||||
property string selectedAccent: storedMulti.accent || multiDefaults.accent || ""
|
||||
property var flavorOptions: {
|
||||
if (!isMultiVariant || !activeThemeVariants?.flavors)
|
||||
return [];
|
||||
return activeThemeVariants.flavors.filter(f => f.mode === colorMode || f.mode === "both");
|
||||
}
|
||||
property var flavorNames: flavorOptions.map(f => f.name)
|
||||
property int flavorIndex: {
|
||||
for (var i = 0; i < flavorOptions.length; i++) {
|
||||
if (flavorOptions[i].id === selectedFlavor)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
property string selectedVariant: activeThemeId ? SettingsData.getRegistryThemeVariant(activeThemeId, activeThemeVariants?.default || "") : ""
|
||||
property var variantNames: {
|
||||
if (!activeThemeVariants?.options)
|
||||
@@ -691,10 +661,111 @@ Item {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: flavorButtonGroup.implicitHeight
|
||||
clip: true
|
||||
visible: variantSelector.isMultiVariant && variantSelector.flavorOptions.length > 1
|
||||
|
||||
DankButtonGroup {
|
||||
id: flavorButtonGroup
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
buttonPadding: parent.width < 400 ? Theme.spacingS : Theme.spacingL
|
||||
minButtonWidth: parent.width < 400 ? 44 : 64
|
||||
textSize: parent.width < 400 ? Theme.fontSizeSmall : Theme.fontSizeMedium
|
||||
model: variantSelector.flavorNames
|
||||
currentIndex: variantSelector.flavorIndex
|
||||
selectionMode: "single"
|
||||
onAnimationCompleted: {
|
||||
if (currentIndex < 0 || currentIndex >= variantSelector.flavorOptions.length)
|
||||
return;
|
||||
const flavorId = variantSelector.flavorOptions[currentIndex]?.id;
|
||||
if (!flavorId || flavorId === variantSelector.selectedFlavor)
|
||||
return;
|
||||
Theme.screenTransition();
|
||||
SettingsData.setRegistryThemeMultiVariant(variantSelector.activeThemeId, flavorId, variantSelector.selectedAccent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: accentColorsGrid.implicitHeight
|
||||
visible: variantSelector.isMultiVariant && variantSelector.activeThemeVariants?.accents?.length > 0
|
||||
|
||||
Grid {
|
||||
id: accentColorsGrid
|
||||
property int accentCount: variantSelector.activeThemeVariants?.accents?.length ?? 0
|
||||
property int dotSize: parent.width < 300 ? 28 : 32
|
||||
columns: accentCount > 0 ? Math.ceil(accentCount / 2) : 1
|
||||
rowSpacing: Theme.spacingS
|
||||
columnSpacing: Theme.spacingS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Repeater {
|
||||
model: variantSelector.activeThemeVariants?.accents || []
|
||||
|
||||
Rectangle {
|
||||
required property var modelData
|
||||
required property int index
|
||||
property string accentId: modelData.id
|
||||
property bool isSelected: accentId === variantSelector.selectedAccent
|
||||
width: accentColorsGrid.dotSize
|
||||
height: accentColorsGrid.dotSize
|
||||
radius: width / 2
|
||||
color: modelData.color || Theme.primary
|
||||
border.color: Theme.outline
|
||||
border.width: isSelected ? 2 : 1
|
||||
scale: isSelected ? 1.1 : 1
|
||||
|
||||
Rectangle {
|
||||
width: accentNameText.contentWidth + Theme.spacingS * 2
|
||||
height: accentNameText.contentHeight + Theme.spacingXS * 2
|
||||
color: Theme.surfaceContainer
|
||||
radius: Theme.cornerRadius
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingXS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: accentMouseArea.containsMouse
|
||||
|
||||
StyledText {
|
||||
id: accentNameText
|
||||
text: modelData.name
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: accentMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (parent.isSelected)
|
||||
return;
|
||||
Theme.screenTransition();
|
||||
SettingsData.setRegistryThemeMultiVariant(variantSelector.activeThemeId, variantSelector.selectedFlavor, parent.accentId);
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: variantButtonGroup.implicitHeight
|
||||
clip: true
|
||||
visible: !variantSelector.isMultiVariant && variantSelector.variantNames.length > 0
|
||||
|
||||
DankButtonGroup {
|
||||
id: variantButtonGroup
|
||||
@@ -742,6 +813,7 @@ Item {
|
||||
tab: "theme"
|
||||
tags: ["light", "dark", "mode", "appearance"]
|
||||
title: I18n.tr("Color Mode")
|
||||
settingKey: "colorMode"
|
||||
iconName: "contrast"
|
||||
|
||||
SettingsToggleRow {
|
||||
@@ -762,6 +834,7 @@ Item {
|
||||
tab: "theme"
|
||||
tags: ["transparency", "opacity", "widget", "styling"]
|
||||
title: I18n.tr("Widget Styling")
|
||||
settingKey: "widgetStyling"
|
||||
iconName: "opacity"
|
||||
|
||||
SettingsButtonGroupRow {
|
||||
@@ -847,6 +920,7 @@ Item {
|
||||
tab: "theme"
|
||||
tags: ["niri", "layout", "gaps", "radius", "window"]
|
||||
title: I18n.tr("Niri Layout Overrides")
|
||||
settingKey: "niriLayout"
|
||||
iconName: "crop_square"
|
||||
visible: CompositorService.isNiri
|
||||
|
||||
@@ -917,6 +991,8 @@ Item {
|
||||
SettingsCard {
|
||||
tab: "theme"
|
||||
tags: ["modal", "darken", "background", "overlay"]
|
||||
title: I18n.tr("Modal Background")
|
||||
settingKey: "modalBackground"
|
||||
|
||||
SettingsToggleRow {
|
||||
tab: "theme"
|
||||
@@ -933,6 +1009,7 @@ Item {
|
||||
tab: "theme"
|
||||
tags: ["applications", "portal", "dark", "terminal"]
|
||||
title: I18n.tr("Applications")
|
||||
settingKey: "applications"
|
||||
iconName: "terminal"
|
||||
|
||||
SettingsToggleRow {
|
||||
@@ -960,6 +1037,7 @@ Item {
|
||||
tab: "theme"
|
||||
tags: ["matugen", "templates", "theming"]
|
||||
title: I18n.tr("Matugen Templates")
|
||||
settingKey: "matugenTemplates"
|
||||
iconName: "auto_awesome"
|
||||
visible: Theme.matugenAvailable
|
||||
|
||||
@@ -1202,6 +1280,8 @@ Item {
|
||||
SettingsCard {
|
||||
tab: "theme"
|
||||
tags: ["icon", "theme", "system"]
|
||||
title: I18n.tr("Icon Theme")
|
||||
settingKey: "iconTheme"
|
||||
|
||||
SettingsDropdownRow {
|
||||
tab: "theme"
|
||||
@@ -1227,6 +1307,7 @@ Item {
|
||||
tab: "theme"
|
||||
tags: ["system", "app", "theming", "gtk", "qt"]
|
||||
title: I18n.tr("System App Theming")
|
||||
settingKey: "systemAppTheming"
|
||||
iconName: "extension"
|
||||
visible: Theme.matugenAvailable
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -26,6 +27,7 @@ Item {
|
||||
tab: "time"
|
||||
tags: ["time", "clock", "format", "24hour"]
|
||||
title: I18n.tr("Time Format")
|
||||
settingKey: "timeFormat"
|
||||
iconName: "schedule"
|
||||
|
||||
SettingsToggleRow {
|
||||
@@ -53,6 +55,7 @@ Item {
|
||||
tab: "time"
|
||||
tags: ["date", "format", "calendar"]
|
||||
title: I18n.tr("Date Format")
|
||||
settingKey: "dateFormat"
|
||||
iconName: "calendar_today"
|
||||
|
||||
SettingsDropdownRow {
|
||||
@@ -325,6 +328,7 @@ Item {
|
||||
tab: "time"
|
||||
tags: ["weather", "enable", "forecast"]
|
||||
title: I18n.tr("Weather")
|
||||
settingKey: "weather"
|
||||
iconName: "cloud"
|
||||
|
||||
SettingsToggleRow {
|
||||
@@ -546,6 +550,7 @@ Item {
|
||||
tab: "time"
|
||||
tags: ["weather", "current", "display"]
|
||||
title: I18n.tr("Current Weather")
|
||||
settingKey: "weather"
|
||||
iconName: "visibility"
|
||||
visible: SettingsData.weatherEnabled
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
@@ -71,6 +72,7 @@ Item {
|
||||
tab: "typography"
|
||||
tags: ["font", "family", "text", "typography"]
|
||||
title: I18n.tr("Typography")
|
||||
settingKey: "typography"
|
||||
iconName: "text_fields"
|
||||
|
||||
SettingsDropdownRow {
|
||||
@@ -206,6 +208,7 @@ Item {
|
||||
tab: "typography"
|
||||
tags: ["animation", "speed", "motion", "duration"]
|
||||
title: I18n.tr("Animation Speed")
|
||||
settingKey: "animationSpeed"
|
||||
iconName: "animation"
|
||||
|
||||
Item {
|
||||
|
||||
@@ -28,6 +28,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -37,6 +38,7 @@ Item {
|
||||
tab: "wallpaper"
|
||||
tags: ["background", "image", "picture"]
|
||||
title: I18n.tr("Wallpaper")
|
||||
settingKey: "wallpaper"
|
||||
iconName: "wallpaper"
|
||||
|
||||
Row {
|
||||
@@ -1186,8 +1188,9 @@ Item {
|
||||
SettingsCard {
|
||||
tab: "wallpaper"
|
||||
tags: ["external", "disable", "swww", "hyprpaper", "swaybg"]
|
||||
iconName: "wallpaper"
|
||||
title: I18n.tr("External Wallpaper Management", "wallpaper settings external management")
|
||||
settingKey: "disableWallpaper"
|
||||
iconName: "wallpaper"
|
||||
|
||||
SettingsToggleRow {
|
||||
tab: "wallpaper"
|
||||
@@ -1215,6 +1218,8 @@ Item {
|
||||
SettingsCard {
|
||||
tab: "wallpaper"
|
||||
tags: ["blur", "layer", "niri", "compositor"]
|
||||
title: I18n.tr("Blur Wallpaper Layer")
|
||||
settingKey: "blurWallpaper"
|
||||
visible: CompositorService.isNiri
|
||||
|
||||
SettingsToggleRow {
|
||||
|
||||
@@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
@@ -16,6 +17,46 @@ Item {
|
||||
|
||||
property string text: ""
|
||||
property string description: ""
|
||||
|
||||
readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey
|
||||
|
||||
function findParentFlickable() {
|
||||
let p = root.parent;
|
||||
while (p) {
|
||||
if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem"))
|
||||
return p;
|
||||
p = p.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!settingKey)
|
||||
return;
|
||||
let flickable = findParentFlickable();
|
||||
if (flickable)
|
||||
SettingsSearchService.registerCard(settingKey, root, flickable);
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
if (settingKey)
|
||||
SettingsSearchService.unregisterCard(settingKey);
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.primary, root.isHighlighted ? 0.2 : 0)
|
||||
visible: root.isHighlighted
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property alias model: buttonGroup.model
|
||||
property alias currentIndex: buttonGroup.currentIndex
|
||||
property alias selectionMode: buttonGroup.selectionMode
|
||||
|
||||
@@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
StyledRect {
|
||||
@@ -12,6 +13,7 @@ StyledRect {
|
||||
|
||||
property string tab: ""
|
||||
property var tags: []
|
||||
property string settingKey: ""
|
||||
|
||||
property string title: ""
|
||||
property string iconName: ""
|
||||
@@ -20,6 +22,8 @@ StyledRect {
|
||||
|
||||
default property alias content: contentColumn.children
|
||||
|
||||
readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey
|
||||
|
||||
width: parent?.width ?? 0
|
||||
height: {
|
||||
var hasHeader = root.title !== "" || root.iconName !== "";
|
||||
@@ -37,6 +41,32 @@ StyledRect {
|
||||
readonly property bool hasHeader: root.title !== "" || root.iconName !== ""
|
||||
property bool userToggledCollapse: false
|
||||
|
||||
function findParentFlickable() {
|
||||
let p = root.parent;
|
||||
while (p) {
|
||||
if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem")) {
|
||||
return p;
|
||||
}
|
||||
p = p.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (settingKey) {
|
||||
let flickable = findParentFlickable();
|
||||
if (flickable) {
|
||||
SettingsSearchService.registerCard(settingKey, root, flickable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
if (settingKey) {
|
||||
SettingsSearchService.unregisterCard(settingKey);
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on height {
|
||||
enabled: root.userToggledCollapse
|
||||
NumberAnimation {
|
||||
@@ -49,6 +79,26 @@ StyledRect {
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: highlightBorder
|
||||
anchors.fill: parent
|
||||
anchors.margins: -2
|
||||
radius: root.radius + 2
|
||||
color: "transparent"
|
||||
border.width: 2
|
||||
border.color: Theme.primary
|
||||
opacity: root.isHighlighted ? 1 : 0
|
||||
visible: opacity > 0
|
||||
z: 100
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
DankDropdown {
|
||||
@@ -10,6 +12,45 @@ DankDropdown {
|
||||
property var tags: []
|
||||
property string settingKey: ""
|
||||
|
||||
readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey
|
||||
|
||||
width: parent?.width ?? 0
|
||||
addHorizontalPadding: true
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.primary, root.isHighlighted ? 0.2 : 0)
|
||||
visible: root.isHighlighted
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findParentFlickable() {
|
||||
let p = root.parent;
|
||||
while (p) {
|
||||
if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem"))
|
||||
return p;
|
||||
p = p.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!settingKey)
|
||||
return;
|
||||
let flickable = findParentFlickable();
|
||||
if (flickable)
|
||||
SettingsSearchService.registerCard(settingKey, root, flickable);
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
if (settingKey)
|
||||
SettingsSearchService.unregisterCard(settingKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
@@ -16,6 +17,45 @@ Item {
|
||||
|
||||
property string text: ""
|
||||
property string description: ""
|
||||
|
||||
readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey
|
||||
|
||||
function findParentFlickable() {
|
||||
let p = root.parent;
|
||||
while (p) {
|
||||
if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem"))
|
||||
return p;
|
||||
p = p.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!settingKey)
|
||||
return;
|
||||
let flickable = findParentFlickable();
|
||||
if (flickable)
|
||||
SettingsSearchService.registerCard(settingKey, root, flickable);
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
if (settingKey)
|
||||
SettingsSearchService.unregisterCard(settingKey);
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.primary, root.isHighlighted ? 0.2 : 0)
|
||||
visible: root.isHighlighted
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
property alias value: slider.value
|
||||
property alias minimum: slider.minimum
|
||||
property alias maximum: slider.maximum
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
DankToggle {
|
||||
@@ -10,5 +12,44 @@ DankToggle {
|
||||
property var tags: []
|
||||
property string settingKey: ""
|
||||
|
||||
readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey
|
||||
|
||||
width: parent?.width ?? 0
|
||||
|
||||
function findParentFlickable() {
|
||||
let p = root.parent;
|
||||
while (p) {
|
||||
if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem"))
|
||||
return p;
|
||||
p = p.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!settingKey)
|
||||
return;
|
||||
let flickable = findParentFlickable();
|
||||
if (flickable)
|
||||
SettingsSearchService.registerCard(settingKey, root, flickable);
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
if (settingKey)
|
||||
SettingsSearchService.unregisterCard(settingKey);
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.primary, root.isHighlighted ? 0.2 : 0)
|
||||
visible: root.isHighlighted
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -932,6 +932,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
@@ -15,6 +15,7 @@ Item {
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
topPadding: 4
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
@@ -23,8 +24,11 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "view_module"
|
||||
title: I18n.tr("Workspace Settings")
|
||||
settingKey: "workspaceSettings"
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "showWorkspaceIndex"
|
||||
tags: ["workspace", "index", "numbers", "labels"]
|
||||
text: I18n.tr("Workspace Index Numbers")
|
||||
description: I18n.tr("Show workspace index numbers in the top bar workspace switcher")
|
||||
checked: SettingsData.showWorkspaceIndex
|
||||
@@ -32,6 +36,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "showWorkspacePadding"
|
||||
tags: ["workspace", "padding", "minimum"]
|
||||
text: I18n.tr("Workspace Padding")
|
||||
description: I18n.tr("Always show a minimum of 3 workspaces, even if fewer are available")
|
||||
checked: SettingsData.showWorkspacePadding
|
||||
@@ -39,6 +45,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "showWorkspaceApps"
|
||||
tags: ["workspace", "apps", "icons", "applications"]
|
||||
text: I18n.tr("Show Workspace Apps")
|
||||
description: I18n.tr("Display application icons in workspace indicators")
|
||||
checked: SettingsData.showWorkspaceApps
|
||||
@@ -87,6 +95,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "workspacesPerMonitor"
|
||||
tags: ["workspace", "per-monitor", "multi-monitor"]
|
||||
text: I18n.tr("Per-Monitor Workspaces")
|
||||
description: I18n.tr("Show only workspaces belonging to each specific monitor.")
|
||||
checked: SettingsData.workspacesPerMonitor
|
||||
@@ -94,6 +104,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "showOccupiedWorkspacesOnly"
|
||||
tags: ["workspace", "occupied", "active", "windows"]
|
||||
text: I18n.tr("Show Occupied Workspaces Only")
|
||||
description: I18n.tr("Display only workspaces that contain windows")
|
||||
checked: SettingsData.showOccupiedWorkspacesOnly
|
||||
@@ -102,6 +114,8 @@ Item {
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "dwlShowAllTags"
|
||||
tags: ["dwl", "tags", "workspace"]
|
||||
text: I18n.tr("Show All Tags")
|
||||
description: I18n.tr("Show all 9 tags instead of only occupied tags (DWL only)")
|
||||
checked: SettingsData.dwlShowAllTags
|
||||
@@ -114,6 +128,7 @@ Item {
|
||||
width: parent.width
|
||||
iconName: "label"
|
||||
title: I18n.tr("Named Workspace Icons")
|
||||
settingKey: "workspaceIcons"
|
||||
visible: SettingsData.hasNamedWorkspaces()
|
||||
|
||||
StyledText {
|
||||
|
||||
207
quickshell/Services/SettingsSearchService.qml
Normal file
207
quickshell/Services/SettingsSearchService.qml
Normal file
@@ -0,0 +1,207 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property string query: ""
|
||||
property var results: []
|
||||
property string targetSection: ""
|
||||
property string highlightSection: ""
|
||||
property var registeredCards: ({})
|
||||
property var settingsIndex: []
|
||||
property bool indexLoaded: false
|
||||
|
||||
readonly property var conditionMap: ({
|
||||
"isNiri": () => CompositorService.isNiri,
|
||||
"isHyprland": () => CompositorService.isHyprland,
|
||||
"isDwl": () => CompositorService.isDwl,
|
||||
"keybindsAvailable": () => KeybindsService.available,
|
||||
"soundsAvailable": () => AudioService.soundsAvailable,
|
||||
"cupsAvailable": () => CupsService.cupsAvailable,
|
||||
"networkNotLegacy": () => !NetworkService.usingLegacy,
|
||||
"dmsConnected": () => DMSService.isConnected && DMSService.apiVersion >= 23,
|
||||
"matugenAvailable": () => Theme.matugenAvailable
|
||||
})
|
||||
|
||||
Component.onCompleted: indexFile.reload()
|
||||
|
||||
FileView {
|
||||
id: indexFile
|
||||
path: Qt.resolvedUrl("../translations/settings_search_index.json")
|
||||
onLoaded: {
|
||||
try {
|
||||
root.settingsIndex = JSON.parse(text());
|
||||
root.indexLoaded = true;
|
||||
} catch (e) {
|
||||
console.warn("SettingsSearchService: Failed to parse index:", e);
|
||||
root.settingsIndex = [];
|
||||
}
|
||||
}
|
||||
onLoadFailed: error => console.warn("SettingsSearchService: Failed to load index:", error)
|
||||
}
|
||||
|
||||
function registerCard(settingKey, item, flickable) {
|
||||
if (!settingKey)
|
||||
return;
|
||||
registeredCards[settingKey] = {
|
||||
item: item,
|
||||
flickable: flickable
|
||||
};
|
||||
if (targetSection === settingKey)
|
||||
scrollTimer.restart();
|
||||
}
|
||||
|
||||
function unregisterCard(settingKey) {
|
||||
if (!settingKey)
|
||||
return;
|
||||
let cards = registeredCards;
|
||||
delete cards[settingKey];
|
||||
registeredCards = cards;
|
||||
}
|
||||
|
||||
function navigateToSection(section) {
|
||||
targetSection = section;
|
||||
if (registeredCards[section])
|
||||
scrollTimer.restart();
|
||||
}
|
||||
|
||||
function scrollToTarget() {
|
||||
if (!targetSection)
|
||||
return;
|
||||
const entry = registeredCards[targetSection];
|
||||
if (!entry || !entry.item || !entry.flickable)
|
||||
return;
|
||||
const flickable = entry.flickable;
|
||||
const item = entry.item;
|
||||
const contentItem = flickable.contentItem;
|
||||
|
||||
if (!contentItem)
|
||||
return;
|
||||
const mapped = item.mapToItem(contentItem, 0, 0);
|
||||
const maxY = Math.max(0, flickable.contentHeight - flickable.height);
|
||||
const targetY = Math.min(maxY, Math.max(0, mapped.y - 16));
|
||||
flickable.contentY = targetY;
|
||||
|
||||
highlightSection = targetSection;
|
||||
targetSection = "";
|
||||
highlightTimer.restart();
|
||||
}
|
||||
|
||||
function clearHighlight() {
|
||||
highlightSection = "";
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: scrollTimer
|
||||
interval: 50
|
||||
onTriggered: root.scrollToTarget()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: highlightTimer
|
||||
interval: 2500
|
||||
onTriggered: root.highlightSection = ""
|
||||
}
|
||||
|
||||
function checkCondition(item) {
|
||||
if (!item.conditionKey)
|
||||
return true;
|
||||
const condFn = conditionMap[item.conditionKey];
|
||||
if (!condFn)
|
||||
return true;
|
||||
return condFn();
|
||||
}
|
||||
|
||||
function translateItem(item) {
|
||||
return {
|
||||
section: item.section,
|
||||
label: I18n.tr(item.label),
|
||||
tabIndex: item.tabIndex,
|
||||
category: I18n.tr(item.category),
|
||||
keywords: item.keywords || [],
|
||||
icon: item.icon || "settings",
|
||||
description: item.description ? I18n.tr(item.description) : "",
|
||||
conditionKey: item.conditionKey
|
||||
};
|
||||
}
|
||||
|
||||
function search(text) {
|
||||
query = text;
|
||||
if (!text) {
|
||||
results = [];
|
||||
return;
|
||||
}
|
||||
|
||||
const queryLower = text.toLowerCase().trim();
|
||||
const queryWords = queryLower.split(/\s+/).filter(w => w.length > 0);
|
||||
const scored = [];
|
||||
|
||||
for (const item of settingsIndex) {
|
||||
if (!checkCondition(item))
|
||||
continue;
|
||||
|
||||
const translated = translateItem(item);
|
||||
const labelLower = translated.label.toLowerCase();
|
||||
const categoryLower = translated.category.toLowerCase();
|
||||
let score = 0;
|
||||
|
||||
if (labelLower === queryLower) {
|
||||
score = 10000;
|
||||
} else if (labelLower.startsWith(queryLower)) {
|
||||
score = 5000;
|
||||
} else if (labelLower.includes(queryLower)) {
|
||||
score = 1000;
|
||||
} else if (categoryLower.includes(queryLower)) {
|
||||
score = 500;
|
||||
}
|
||||
|
||||
if (score === 0) {
|
||||
for (const keyword of item.keywords) {
|
||||
if (keyword.startsWith(queryLower)) {
|
||||
score = Math.max(score, 800);
|
||||
break;
|
||||
}
|
||||
if (keyword.includes(queryLower)) {
|
||||
score = Math.max(score, 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (score === 0 && queryWords.length > 1) {
|
||||
let allMatch = true;
|
||||
for (const word of queryWords) {
|
||||
const inLabel = labelLower.includes(word);
|
||||
const inKeywords = item.keywords.some(k => k.includes(word));
|
||||
const inCategory = categoryLower.includes(word);
|
||||
if (!inLabel && !inKeywords && !inCategory) {
|
||||
allMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allMatch)
|
||||
score = 300;
|
||||
}
|
||||
|
||||
if (score > 0) {
|
||||
scored.push({
|
||||
item: translated,
|
||||
score: score
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
scored.sort((a, b) => b.score - a.score);
|
||||
results = scored.slice(0, 15).map(s => s.item);
|
||||
}
|
||||
|
||||
function clear() {
|
||||
query = "";
|
||||
results = [];
|
||||
}
|
||||
}
|
||||
370
quickshell/translations/extract_settings_index.py
Executable file
370
quickshell/translations/extract_settings_index.py
Executable file
@@ -0,0 +1,370 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
ABBREVIATIONS = {
|
||||
"on-screen displays": ["osd"],
|
||||
"on-screen display": ["osd"],
|
||||
"do not disturb": ["dnd"],
|
||||
"keyboard shortcuts": ["keybinds", "hotkeys", "bindings", "keys"],
|
||||
"notifications": ["notif", "notifs", "alerts"],
|
||||
"notification": ["notif", "alert"],
|
||||
"wallpaper": ["background", "bg", "image", "picture", "desktop"],
|
||||
"transparency": ["opacity", "alpha", "translucent", "transparent"],
|
||||
"visibility": ["visible", "hide", "show", "hidden", "autohide", "auto-hide"],
|
||||
"temperature": ["temp", "celsius", "fahrenheit"],
|
||||
"configuration": ["config", "configure", "setup"],
|
||||
"applications": ["apps", "programs"],
|
||||
"application": ["app", "program"],
|
||||
"animation": ["motion", "transition", "animate", "animations"],
|
||||
"typography": ["font", "fonts", "text", "typeface"],
|
||||
"workspaces": ["workspace", "desktops", "virtual"],
|
||||
"workspace": ["desktop", "virtual"],
|
||||
"bluetooth": ["bt"],
|
||||
"network": ["wifi", "wi-fi", "ethernet", "internet", "connection", "wireless"],
|
||||
"display": ["monitor", "screen", "output"],
|
||||
"displays": ["monitors", "screens", "outputs"],
|
||||
"brightness": ["bright", "dim", "backlight"],
|
||||
"volume": ["audio", "sound", "speaker", "loudness"],
|
||||
"battery": ["power", "charge", "charging"],
|
||||
"clock": ["time", "watch"],
|
||||
"calendar": ["date", "day", "month", "year"],
|
||||
"launcher": ["app drawer", "app menu", "start menu", "applications"],
|
||||
"dock": ["taskbar", "panel"],
|
||||
"bar": ["panel", "taskbar", "topbar", "statusbar"],
|
||||
"theme": ["appearance", "look", "style", "colors", "colour"],
|
||||
"color": ["colour", "hue", "tint"],
|
||||
"colors": ["colours", "palette"],
|
||||
"dark": ["night", "dark mode"],
|
||||
"light": ["day", "light mode"],
|
||||
"lock screen": ["lockscreen", "login", "security"],
|
||||
"power": ["shutdown", "reboot", "restart", "suspend", "hibernate", "sleep"],
|
||||
"idle": ["afk", "inactive", "timeout", "screensaver"],
|
||||
"gamma": ["color temperature", "night light", "blue light", "redshift"],
|
||||
"media player": ["mpris", "music", "audio", "playback"],
|
||||
"clipboard": ["copy", "paste", "cliphist", "history"],
|
||||
"updater": ["updates", "upgrade", "packages"],
|
||||
"plugins": ["extensions", "addons", "widgets"],
|
||||
"spacing": ["gap", "gaps", "margin", "margins", "padding"],
|
||||
"corner": ["corners", "rounded", "radius", "round"],
|
||||
"matugen": ["dynamic", "wallpaper colors", "material"],
|
||||
"running apps": ["taskbar", "windows", "active", "open"],
|
||||
"weather": ["forecast", "temperature", "climate"],
|
||||
"sounds": ["audio", "effects", "sfx"],
|
||||
"printers": ["print", "cups", "printing"],
|
||||
"widgets": ["components", "modules"],
|
||||
}
|
||||
|
||||
CATEGORY_KEYWORDS = {
|
||||
"Personalization": ["customize", "custom", "personal", "appearance"],
|
||||
"Time & Weather": ["clock", "forecast", "date"],
|
||||
"Keyboard Shortcuts": ["keys", "bindings", "hotkey"],
|
||||
"Dank Bar": ["panel", "topbar", "statusbar"],
|
||||
"Workspaces": ["virtual desktops", "spaces"],
|
||||
"Dock": ["taskbar", "launcher bar"],
|
||||
"Network": ["connectivity", "online"],
|
||||
"System": ["os", "linux"],
|
||||
"Launcher": ["start", "menu", "drawer"],
|
||||
"Theme & Colors": ["appearance", "look", "style", "scheme"],
|
||||
"Lock Screen": ["security", "login", "password"],
|
||||
"Plugins": ["extend", "addon"],
|
||||
"About": ["info", "version", "credits", "help"],
|
||||
"Typography & Motion": ["fonts", "animation", "text"],
|
||||
"Sounds": ["audio", "sfx", "effects"],
|
||||
"Media Player": ["music", "spotify", "mpris"],
|
||||
"Notifications": ["alerts", "messages", "toast"],
|
||||
"On-screen Displays": ["osd", "indicator", "popup"],
|
||||
"Running Apps": ["windows", "tasks", "active"],
|
||||
"System Updater": ["packages", "upgrade"],
|
||||
"Power & Sleep": ["shutdown", "suspend", "energy"],
|
||||
"Displays": ["monitor", "screen", "resolution"],
|
||||
"Desktop Widgets": ["conky", "desktop clock"],
|
||||
}
|
||||
|
||||
TAB_INDEX_MAP = {
|
||||
"WallpaperTab.qml": 0,
|
||||
"TimeWeatherTab.qml": 1,
|
||||
"KeybindsTab.qml": 2,
|
||||
"DankBarTab.qml": 3,
|
||||
"WorkspacesTab.qml": 4,
|
||||
"DockTab.qml": 5,
|
||||
"NetworkTab.qml": 7,
|
||||
"PrinterTab.qml": 8,
|
||||
"LauncherTab.qml": 9,
|
||||
"ThemeColorsTab.qml": 10,
|
||||
"LockScreenTab.qml": 11,
|
||||
"PluginsTab.qml": 12,
|
||||
"AboutTab.qml": 13,
|
||||
"TypographyMotionTab.qml": 14,
|
||||
"SoundsTab.qml": 15,
|
||||
"MediaPlayerTab.qml": 16,
|
||||
"NotificationsTab.qml": 17,
|
||||
"OSDTab.qml": 18,
|
||||
"RunningAppsTab.qml": 19,
|
||||
"SystemUpdaterTab.qml": 20,
|
||||
"PowerSleepTab.qml": 21,
|
||||
"WidgetsTab.qml": 22,
|
||||
"ClipboardTab.qml": 23,
|
||||
"DisplayConfigTab.qml": 24,
|
||||
"GammaControlTab.qml": 25,
|
||||
"DisplayWidgetsTab.qml": 26,
|
||||
"DesktopWidgetsTab.qml": 27,
|
||||
}
|
||||
|
||||
TAB_CATEGORY_MAP = {
|
||||
0: "Personalization",
|
||||
1: "Time & Weather",
|
||||
2: "Keyboard Shortcuts",
|
||||
3: "Dank Bar",
|
||||
4: "Workspaces",
|
||||
5: "Dock",
|
||||
7: "Network",
|
||||
8: "System",
|
||||
9: "Launcher",
|
||||
10: "Theme & Colors",
|
||||
11: "Lock Screen",
|
||||
12: "Plugins",
|
||||
13: "About",
|
||||
14: "Typography & Motion",
|
||||
15: "Sounds",
|
||||
16: "Media Player",
|
||||
17: "Notifications",
|
||||
18: "On-screen Displays",
|
||||
19: "Running Apps",
|
||||
20: "System Updater",
|
||||
21: "Power & Sleep",
|
||||
22: "Dank Bar",
|
||||
23: "System",
|
||||
24: "Displays",
|
||||
25: "Displays",
|
||||
26: "Displays",
|
||||
27: "Desktop Widgets",
|
||||
}
|
||||
|
||||
SEARCHABLE_COMPONENTS = [
|
||||
"SettingsCard",
|
||||
"SettingsToggleRow",
|
||||
"SettingsSliderCard",
|
||||
"SettingsDropdownRow",
|
||||
"SettingsButtonGroupRow",
|
||||
"SettingsSliderRow",
|
||||
"SettingsToggleCard",
|
||||
]
|
||||
|
||||
def enrich_keywords(label, description, category, existing_tags):
|
||||
keywords = set(existing_tags)
|
||||
|
||||
label_lower = label.lower()
|
||||
label_words = re.split(r'[\s\-_&/]+', label_lower)
|
||||
keywords.update(w for w in label_words if len(w) > 2)
|
||||
|
||||
for term, aliases in ABBREVIATIONS.items():
|
||||
if term in label_lower:
|
||||
keywords.update(aliases)
|
||||
|
||||
if description:
|
||||
desc_lower = description.lower()
|
||||
desc_words = re.split(r'[\s\-_&/,.]+', desc_lower)
|
||||
keywords.update(w for w in desc_words if len(w) > 3 and w.isalpha())
|
||||
for term, aliases in ABBREVIATIONS.items():
|
||||
if term in desc_lower:
|
||||
keywords.update(aliases)
|
||||
|
||||
if category in CATEGORY_KEYWORDS:
|
||||
keywords.update(CATEGORY_KEYWORDS[category])
|
||||
|
||||
cat_lower = category.lower()
|
||||
cat_words = re.split(r'[\s\-_&/]+', cat_lower)
|
||||
keywords.update(w for w in cat_words if len(w) > 2)
|
||||
|
||||
stopwords = {'the', 'and', 'for', 'with', 'from', 'this', 'that', 'are', 'was',
|
||||
'will', 'can', 'has', 'have', 'been', 'when', 'your', 'use', 'used',
|
||||
'using', 'instead', 'like', 'such', 'also', 'only', 'which', 'each',
|
||||
'other', 'some', 'into', 'than', 'then', 'them', 'these', 'those'}
|
||||
keywords = {k for k in keywords if k not in stopwords and len(k) > 1}
|
||||
|
||||
return sorted(keywords)
|
||||
|
||||
def extract_i18n_string(value):
|
||||
match = re.search(r'I18n\.tr\(["\']([^"\']+)["\']', value)
|
||||
if match:
|
||||
return match.group(1)
|
||||
match = re.search(r'^["\']([^"\']+)["\']$', value.strip())
|
||||
if match:
|
||||
return match.group(1)
|
||||
return None
|
||||
|
||||
def extract_tags(value):
|
||||
match = re.search(r'\[([^\]]+)\]', value)
|
||||
if not match:
|
||||
return []
|
||||
content = match.group(1)
|
||||
tags = re.findall(r'["\']([^"\']+)["\']', content)
|
||||
return tags
|
||||
|
||||
def parse_component_block(content, start_pos, component_name):
|
||||
brace_count = 0
|
||||
started = False
|
||||
block_start = start_pos
|
||||
|
||||
for i in range(start_pos, len(content)):
|
||||
if content[i] == '{':
|
||||
if not started:
|
||||
block_start = i
|
||||
started = True
|
||||
brace_count += 1
|
||||
elif content[i] == '}':
|
||||
brace_count -= 1
|
||||
if started and brace_count == 0:
|
||||
return content[block_start:i+1]
|
||||
return ""
|
||||
|
||||
def extract_property(block, prop_name):
|
||||
pattern = rf'{prop_name}\s*:\s*([^\n]+)'
|
||||
match = re.search(pattern, block)
|
||||
if match:
|
||||
return match.group(1).strip()
|
||||
return None
|
||||
|
||||
def find_settings_components(content, filename):
|
||||
results = []
|
||||
tab_index = TAB_INDEX_MAP.get(filename, -1)
|
||||
|
||||
if tab_index == -1:
|
||||
return results
|
||||
|
||||
for component in SEARCHABLE_COMPONENTS:
|
||||
pattern = rf'\b{component}\s*\{{'
|
||||
for match in re.finditer(pattern, content):
|
||||
block = parse_component_block(content, match.start(), component)
|
||||
if not block:
|
||||
continue
|
||||
|
||||
setting_key = extract_property(block, "settingKey")
|
||||
if setting_key:
|
||||
setting_key = setting_key.strip('"\'')
|
||||
|
||||
if not setting_key:
|
||||
continue
|
||||
|
||||
title_raw = extract_property(block, "title")
|
||||
text_raw = extract_property(block, "text")
|
||||
label = None
|
||||
if title_raw:
|
||||
label = extract_i18n_string(title_raw)
|
||||
if not label and text_raw:
|
||||
label = extract_i18n_string(text_raw)
|
||||
|
||||
if not label:
|
||||
continue
|
||||
|
||||
icon_raw = extract_property(block, "iconName")
|
||||
icon = None
|
||||
if icon_raw:
|
||||
icon = icon_raw.strip('"\'')
|
||||
if icon.startswith("{") or "?" in icon:
|
||||
icon = None
|
||||
|
||||
tags_raw = extract_property(block, "tags")
|
||||
tags = []
|
||||
if tags_raw:
|
||||
tags = extract_tags(tags_raw)
|
||||
|
||||
desc_raw = extract_property(block, "description")
|
||||
description = None
|
||||
if desc_raw:
|
||||
description = extract_i18n_string(desc_raw)
|
||||
|
||||
visible_raw = extract_property(block, "visible")
|
||||
condition_key = None
|
||||
if visible_raw:
|
||||
if "CompositorService.isNiri" in visible_raw:
|
||||
condition_key = "isNiri"
|
||||
elif "CompositorService.isHyprland" in visible_raw:
|
||||
condition_key = "isHyprland"
|
||||
elif "KeybindsService.available" in visible_raw:
|
||||
condition_key = "keybindsAvailable"
|
||||
elif "AudioService.soundsAvailable" in visible_raw:
|
||||
condition_key = "soundsAvailable"
|
||||
elif "CupsService.cupsAvailable" in visible_raw:
|
||||
condition_key = "cupsAvailable"
|
||||
elif "NetworkService.usingLegacy" in visible_raw:
|
||||
condition_key = "networkNotLegacy"
|
||||
elif "DMSService.isConnected" in visible_raw:
|
||||
condition_key = "dmsConnected"
|
||||
elif "Theme.matugenAvailable" in visible_raw:
|
||||
condition_key = "matugenAvailable"
|
||||
elif "CompositorService.isDwl" in visible_raw:
|
||||
condition_key = "isDwl"
|
||||
|
||||
category = TAB_CATEGORY_MAP.get(tab_index, "Settings")
|
||||
enriched_keywords = enrich_keywords(label, description, category, tags)
|
||||
|
||||
entry = {
|
||||
"section": setting_key,
|
||||
"label": label,
|
||||
"tabIndex": tab_index,
|
||||
"category": category,
|
||||
"keywords": enriched_keywords,
|
||||
}
|
||||
|
||||
if icon:
|
||||
entry["icon"] = icon
|
||||
if description:
|
||||
entry["description"] = description
|
||||
if condition_key:
|
||||
entry["conditionKey"] = condition_key
|
||||
|
||||
results.append(entry)
|
||||
|
||||
return results
|
||||
|
||||
def extract_settings_index(root_dir):
|
||||
settings_dir = Path(root_dir) / "Modules" / "Settings"
|
||||
all_entries = []
|
||||
seen_keys = set()
|
||||
|
||||
for qml_file in settings_dir.glob("*.qml"):
|
||||
if not qml_file.name.endswith("Tab.qml"):
|
||||
continue
|
||||
|
||||
with open(qml_file, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
entries = find_settings_components(content, qml_file.name)
|
||||
for entry in entries:
|
||||
key = entry["section"]
|
||||
if key not in seen_keys:
|
||||
seen_keys.add(key)
|
||||
all_entries.append(entry)
|
||||
|
||||
return all_entries
|
||||
|
||||
def main():
|
||||
script_dir = Path(__file__).parent
|
||||
root_dir = script_dir.parent
|
||||
|
||||
print("Extracting settings search index...")
|
||||
entries = extract_settings_index(root_dir)
|
||||
|
||||
entries.sort(key=lambda x: (x["tabIndex"], x["label"]))
|
||||
|
||||
output_path = script_dir / "settings_search_index.json"
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(entries, f, indent=2, ensure_ascii=False)
|
||||
|
||||
print(f"Found {len(entries)} searchable settings")
|
||||
print(f"Output: {output_path}")
|
||||
|
||||
conditions = set()
|
||||
for entry in entries:
|
||||
if "conditionKey" in entry:
|
||||
conditions.add(entry["conditionKey"])
|
||||
|
||||
if conditions:
|
||||
print(f"Condition keys found: {', '.join(sorted(conditions))}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
3666
quickshell/translations/settings_search_index.json
Normal file
3666
quickshell/translations/settings_search_index.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user