inital commit

This commit is contained in:
2025-12-28 10:41:44 -06:00
commit e7426264e7
119 changed files with 4953 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
{
"mError": "#f38ba8",
"mHover": "#94e2d5",
"mOnError": "#11111b",
"mOnHover": "#11111b",
"mOnPrimary": "#11111b",
"mOnSecondary": "#11111b",
"mOnSurface": "#cdd6f4",
"mOnSurfaceVariant": "#a3b4eb",
"mOnTertiary": "#11111b",
"mOutline": "#4c4f69",
"mPrimary": "#cba6f7",
"mSecondary": "#fab387",
"mShadow": "#11111b",
"mSurface": "#1e1e2e",
"mSurfaceVariant": "#313244",
"mTertiary": "#94e2d5"
}

View File

@@ -0,0 +1,34 @@
{
"dark": {
"mPrimary": "#b58fff",
"mOnPrimary": "#000000",
"mSecondary": "#c79aff",
"mOnSecondary": "#000000",
"mTertiary": "#d8b4ff",
"mOnTertiary": "#000000",
"mError": "#ff6f9b",
"mOnError": "#000000",
"mSurface": "#000000",
"mOnSurface": "#e8d8ff",
"mSurfaceVariant": "#110d1a",
"mOnSurfaceVariant": "#b58fff",
"mOutline": "#4c3a70",
"mShadow": "#000000"
},
"light": {
"mPrimary": "#8a56d4",
"mOnPrimary": "#ffffff",
"mSecondary": "#a074ff",
"mOnSecondary": "#ffffff",
"mTertiary": "#c79aff",
"mOnTertiary": "#ffffff",
"mError": "#ff6f9b",
"mOnError": "#ffffff",
"mSurface": "#fbf8ff",
"mOnSurface": "#1a1428",
"mSurfaceVariant": "#e8e0f8",
"mOnSurfaceVariant": "#8a56d4",
"mOutline": "#9b85c2",
"mShadow": "#e2d8f5"
}
}

View File

@@ -0,0 +1,31 @@
[colors.primary]
background = "#000000"
foreground = "#e8d8ff"
[colors.cursor]
text = "#000000"
cursor = "#e8d8ff"
[colors.selection]
text = "#e8d8ff"
background = "#4c3a70"
[colors.normal]
black = "#000000"
red = "#ff6f9b"
green = "#a8e6cf"
yellow = "#d8b4ff"
blue = "#b58fff"
magenta = "#c79aff"
cyan = "#e0c1ff"
white = "#e8d8ff"
[colors.bright]
black = "#4c3a70"
red = "#ff8cb3"
green = "#b8f0d8"
yellow = "#e6d1ff"
blue = "#c9a8ff"
magenta = "#d4b8ff"
cyan = "#f0e0ff"
white = "#f5f0ff"

View File

@@ -0,0 +1,31 @@
[colors.primary]
background = "#fbf8ff"
foreground = "#1a1428"
[colors.cursor]
text = "#fbf8ff"
cursor = "#1a1428"
[colors.selection]
text = "#1a1428"
background = "#e8e0f8"
[colors.normal]
black = "#6b5b95"
red = "#ff6f9b"
green = "#6fb58f"
yellow = "#c79aff"
blue = "#8a56d4"
magenta = "#a074ff"
cyan = "#b89fff"
white = "#1a1428"
[colors.bright]
black = "#9b85c2"
red = "#ff8cb3"
green = "#85d7a8"
yellow = "#e0c1ff"
blue = "#b58fff"
magenta = "#c79aff"
cyan = "#d8b4ff"
white = "#120f1f"

View File

@@ -0,0 +1,10 @@
[colors]
foreground=e8d8ff
background=000000
regular0=000000 regular1=ff6f9b regular2=a8e6cf regular3=d8b4ff
regular4=b58fff regular5=c79aff regular6=e0c1ff regular7=e8d8ff
bright0=4c3a70 bright1=ff8cb3 bright2=b8f0d8 bright3=e6d1ff
bright4=c9a8ff bright5=d4b8ff bright6=f0e0ff bright7=f5f0ff
selection-foreground=e8d8ff
selection-background=4c3a70
cursor=000000 e8d8ff

View File

@@ -0,0 +1,10 @@
[colors]
foreground=1a1428
background=fbf8ff
regular0=6b5b95 regular1=ff6f9b regular2=6fb58f regular3=c79aff
regular4=8a56d4 regular5=a074ff regular6=b89fff regular7=1a1428
bright0=9b85c2 bright1=ff8cb3 bright2=85d7a8 bright3=e0c1ff
bright4=b58fff bright5=c79aff bright6=d8b4ff bright7=120f1f
selection-foreground=1a1428
selection-background=e8e0f8
cursor=fbf8ff 1a1428

View File

@@ -0,0 +1,22 @@
palette = 0=#000000
palette = 1=#ff6f9b
palette = 2=#a8e6cf
palette = 3=#d8b4ff
palette = 4=#b58fff
palette = 5=#c79aff
palette = 6=#e0c1ff
palette = 7=#e8d8ff
palette = 8=#4c3a70
palette = 9=#ff8cb3
palette = 10=#b8f0d8
palette = 11=#e6d1ff
palette = 12=#c9a8ff
palette = 13=#d4b8ff
palette = 14=#f0e0ff
palette = 15=#f5f0ff
background = #000000
foreground = #e8d8ff
cursor-color = #e8d8ff
cursor-text = #000000
selection-background = #4c3a70
selection-foreground = #e8d8ff

View File

@@ -0,0 +1,22 @@
palette = 0=#6b5b95
palette = 1=#ff6f9b
palette = 2=#6fb58f
palette = 3=#c79aff
palette = 4=#8a56d4
palette = 5=#a074ff
palette = 6=#b89fff
palette = 7=#1a1428
palette = 8=#9b85c2
palette = 9=#ff8cb3
palette = 10=#85d7a8
palette = 11=#e0c1ff
palette = 12=#b58fff
palette = 13=#c79aff
palette = 14=#d8b4ff
palette = 15=#120f1f
background = #fbf8ff
foreground = #1a1428
cursor-color = #1a1428
cursor-text = #fbf8ff
selection-background = #e8e0f8
selection-foreground = #1a1428

View File

@@ -0,0 +1,22 @@
background #000000
foreground #e8d8ff
selection_background #4c3a70
selection_foreground #e8d8ff
cursor #e8d8ff
cursor_text_color #000000
color0 #000000
color1 #ff6f9b
color2 #a8e6cf
color3 #d8b4ff
color4 #b58fff
color5 #c79aff
color6 #e0c1ff
color7 #e8d8ff
color8 #4c3a70
color9 #ff8cb3
color10 #b8f0d8
color11 #e6d1ff
color12 #c9a8ff
color13 #d4b8ff
color14 #f0e0ff
color15 #f5f0ff

View File

@@ -0,0 +1,22 @@
background #fbf8ff
foreground #1a1428
selection_background #e8e0f8
selection_foreground #1a1428
cursor #1a1428
cursor_text_color #fbf8ff
color0 #6b5b95
color1 #ff6f9b
color2 #6fb58f
color3 #c79aff
color4 #8a56d4
color5 #a074ff
color6 #b89fff
color7 #1a1428
color8 #9b85c2
color9 #ff8cb3
color10 #85d7a8
color11 #e0c1ff
color12 #b58fff
color13 #c79aff
color14 #d8b4ff
color15 #120f1f

View File

@@ -0,0 +1,17 @@
[colors]
ansi = [
"#000000","#ff6f9b","#a8e6cf","#d8b4ff","#b58fff","#c79aff","#e0c1ff","#e8d8ff",
]
background = "#000000"
brights = [
"#4c3a70","#ff8cb3","#b8f0d8","#e6d1ff","#c9a8ff","#d4b8ff","#f0e0ff","#f5f0ff",
]
cursor_bg = "#e8d8ff"
cursor_border = "#e8d8ff"
cursor_fg = "#000000"
foreground = "#e8d8ff"
selection_bg = "#4c3a70"
selection_fg = "#e8d8ff"
[metadata]
name = "LilacAMOLED (Dark)"

View File

@@ -0,0 +1,17 @@
[colors]
ansi = [
"#6b5b95","#ff6f9b","#6fb58f","#c79aff","#8a56d4","#a074ff","#b89fff","#1a1428",
]
background = "#fbf8ff"
brights = [
"#9b85c2","#ff8cb3","#85d7a8","#e0c1ff","#b58fff","#c79aff","#d8b4ff","#120f1f",
]
cursor_bg = "#1a1428"
cursor_border = "#1a1428"
cursor_fg = "#fbf8ff"
foreground = "#1a1428"
selection_bg = "#e8e0f8"
selection_fg = "#1a1428"
[metadata]
name = "LilacAMOLED (Light)"

View File

@@ -0,0 +1,38 @@
{
"dark": {
"mPrimary": "#ea9a97",
"mOnPrimary": "#232136",
"mSecondary": "#9ccfd8",
"mOnSecondary": "#232136",
"mTertiary": "#3e8fb0",
"mOnTertiary": "#e0def4",
"mError": "#eb6f92",
"mOnError": "#232136",
"mSurface": "#232136",
"mOnSurface": "#e0def4",
"mSurfaceVariant": "#393552",
"mOnSurfaceVariant": "#908caa",
"mOutline": "#44415a",
"mShadow": "#232136",
"mHover": "#56526e",
"mOnHover": "#e0def4"
},
"light": {
"mPrimary": "#d7827e",
"mOnPrimary": "#faf4ed",
"mSecondary": "#56949f",
"mOnSecondary": "#faf4ed",
"mTertiary": "#286983",
"mOnTertiary": "#faf4ed",
"mError": "#b4637a",
"mOnError": "#faf4ed",
"mSurface": "#fffaf3",
"mOnSurface": "#575279",
"mSurfaceVariant": "#f2e9e1",
"mOnSurfaceVariant": "#797593",
"mOutline": "#dfdad9",
"mShadow": "#faf4ed",
"mHover": "#cecacd",
"mOnHover": "#575279"
}
}

View File

@@ -0,0 +1,74 @@
# Colors section of "Alacritty - TOML configuration file format"
# https://github.com/alacritty/alacritty/blob/master/extra/man/alacritty.5.scd#colors
[colors.primary]
foreground = "#e0def4"
background = "#232136"
dim_foreground = "#908caa"
bright_foreground = "#e0def4"
[colors.cursor]
text = "None"
cursor = "None"
[colors.vi_mode_cursor]
text = "None"
cursor = "None"
[colors.search.matches]
foreground = "#908caa"
background = "#393552"
[colors.search.focused_match]
foreground = "#232136"
background = "#ea9a97"
[colors.hints.start]
foreground = "#908caa"
background = "#2a273f"
[colors.hints.end]
foreground = "#6e6a86"
background = "#2a273f"
[colors.line_indicator]
foreground = "None"
background = "None"
[colors.footer_bar]
foreground = "#e0def4"
background = "#2a273f"
[colors.selection]
text = "#e0def4"
background = "#44415a"
[colors.normal]
black = "#393552"
red = "#eb6f92"
green = "#3e8fb0"
yellow = "#f6c177"
blue = "#9ccfd8"
magenta = "#c4a7e7"
cyan = "#ea9a97"
white = "#e0def4"
[colors.bright]
black = "#6e6a86"
red = "#eb6f92"
green = "#3e8fb0"
yellow = "#f6c177"
blue = "#9ccfd8"
magenta = "#c4a7e7"
cyan = "#ea9a97"
white = "#e0def4"
[colors.dim]
black = "#6e6a86"
red = "#eb6f92"
green = "#31748f"
yellow = "#f6c177"
blue = "#9ccfd8"
magenta = "#c4a7e7"
cyan = "#ebbcba"
white = "#e0def4"

View File

@@ -0,0 +1,74 @@
# Colors section of "Alacritty - TOML configuration file format"
# https://github.com/alacritty/alacritty/blob/master/extra/man/alacritty.5.scd#colors
[colors.primary]
foreground = "#575279"
background = "#faf4ed"
dim_foreground = "#797593"
bright_foreground = "#575279"
[colors.cursor]
text = "None"
cursor = "None"
[colors.vi_mode_cursor]
text = "None"
cursor = "None"
[colors.search.matches]
foreground = "#797593"
background = "#f2e9e1"
[colors.search.focused_match]
foreground = "#faf4ed"
background = "#d7827e"
[colors.hints.start]
foreground = "#797593"
background = "#fffaf3"
[colors.hints.end]
foreground = "#9893a5"
background = "#fffaf3"
[colors.line_indicator]
foreground = "None"
background = "None"
[colors.footer_bar]
foreground = "#575279"
background = "#fffaf3"
[colors.selection]
text = "#575279"
background = "#dfdad9"
[colors.normal]
black = "#f2e9e1"
red = "#b4637a"
green = "#286983"
yellow = "#ea9d34"
blue = "#56949f"
magenta = "#907aa9"
cyan = "#d7827e"
white = "#575279"
[colors.bright]
black = "#9893a5"
red = "#b4637a"
green = "#286983"
yellow = "#ea9d34"
blue = "#56949f"
magenta = "#907aa9"
cyan = "#d7827e"
white = "#575279"
[colors.dim]
black = "#9893a5"
red = "#b4637a"
green = "#286983"
yellow = "#ea9d34"
blue = "#56949f"
magenta = "#907aa9"
cyan = "#d7827e"
white = "#575279"

View File

@@ -0,0 +1,23 @@
[colors]
foreground=e0def4
background=232136
regular0=393552
regular1=eb6f92
regular2=3e8fb0
regular3=f6c177
regular4=9ccfd8
regular5=c4a7e7
regular6=ea9a97
regular7=e0def4
bright0=6e6a86
bright1=eb6f92
bright2=3e8fb0
bright3=f6c177
bright4=9ccfd8
bright5=c4a7e7
bright6=ea9a97
bright7=e0def4
flash=f6c177

View File

@@ -0,0 +1,23 @@
[colors]
foreground=575279
background=faf4ed
regular0=f2e9e1
regular1=b4637a
regular2=286983
regular3=ea9d34
regular4=56949f
regular5=907aa9
regular6=d7827e
regular7=575279
bright0=9893a5
bright1=b4637a
bright2=286983
bright3=ea9d34
bright4=56949f
bright5=907aa9
bright6=d7827e
bright7=575279
flash=ea9d34

View File

@@ -0,0 +1,22 @@
palette = 0=#393552
palette = 1=#eb6f92
palette = 2=#3e8fb0
palette = 3=#f6c177
palette = 4=#9ccfd8
palette = 5=#c4a7e7
palette = 6=#ea9a97
palette = 7=#e0def4
palette = 8=#6e6a86
palette = 9=#eb6f92
palette = 10=#3e8fb0
palette = 11=#f6c177
palette = 12=#9ccfd8
palette = 13=#c4a7e7
palette = 14=#ea9a97
palette = 15=#e0def4
background = #232136
foreground = #e0def4
cursor-color = #908caa
cursor-text = #e0def4
selection-background = #44415a
selection-foreground = #e0def4

View File

@@ -0,0 +1,22 @@
palette = 0=#f2e9e1
palette = 1=#b4637a
palette = 2=#286983
palette = 3=#ea9d34
palette = 4=#56949f
palette = 5=#907aa9
palette = 6=#d7827e
palette = 7=#575279
palette = 8=#9893a5
palette = 9=#b4637a
palette = 10=#286983
palette = 11=#ea9d34
palette = 12=#56949f
palette = 13=#907aa9
palette = 14=#d7827e
palette = 15=#575279
background = #faf4ed
foreground = #575279
cursor-color = #797593
cursor-text = #faf4ed
selection-background = #dfdad9
selection-foreground = #575279

View File

@@ -0,0 +1,22 @@
color0 #26233a
color1 #eb6f92
color2 #31748f
color3 #f6c177
color4 #9ccfd8
color5 #c4a7e7
color6 #ebbcba
color7 #e0def4
color8 #6e6a86
color9 #eb6f92
color10 #31748f
color11 #f6c177
color12 #9ccfd8
color13 #c4a7e7
color14 #ebbcba
color15 #e0def4
background #232136
selection_foreground #232136
cursor #908caa
cursor_text_color #e0def4
foreground #e0def4
selection_background #6e6a86

View File

@@ -0,0 +1,22 @@
color0 #f2e9e1
color1 #b4637a
color2 #286983
color3 #ea9d34
color4 #56949f
color5 #907aa9
color6 #d7827e
color7 #575279
color8 #9893a5
color9 #b4637a
color10 #286983
color11 #ea9d34
color12 #56949f
color13 #907aa9
color14 #d7827e
color15 #575279
background #faf4ed
selection_foreground #575279
cursor #797593
cursor_text_color #faf4ed
foreground #575279
selection_background #dfdad9

View File

@@ -0,0 +1,33 @@
[colors]
ansi = [
"#393552",
"#eb6f92",
"#9ccfd8",
"#f6c177",
"#3e8fb0",
"#c4a7e7",
"#ea9a97",
"#e0def4",
]
background = "#232136"
brights = [
"#6e6a86",
"#eb6f92",
"#9ccfd8",
"#f6c177",
"#3e8fb0",
"#c4a7e7",
"#ea9a97",
"#e0def4",
]
cursor_bg = "#908caa"
cursor_border = "#908caa"
cursor_fg = "#e0def4"
foreground = "#e0def4"
selection_bg = "#44415a"
selection_fg = "#e0def4"
[colors.indexed]
[metadata]
name = "Noctalia"

View File

@@ -0,0 +1,33 @@
[colors]
ansi = [
"#f2e9e1",
"#b4637a",
"#56949f",
"#ea9d34",
"#286983",
"#907aa9",
"#d7827e",
"#575279",
]
background = "#faf4ed"
brights = [
"#9893a5",
"#b4637a",
"#56949f",
"#ea9d34",
"#286983",
"#907aa9",
"#d7827e",
"#575279",
]
cursor_bg = "#797593"
cursor_border = "#797593"
cursor_fg = "#faf4ed"
foreground = "#575279"
selection_bg = "#dfdad9"
selection_fg = "#575279"
[colors.indexed]
[metadata]
name = "Noctalia"

View File

@@ -0,0 +1,38 @@
{
"dark": {
"mPrimary": "#7a88cf",
"mOnPrimary": "#1f2335",
"mSecondary": "#d7729f",
"mOnSecondary": "#1f2335",
"mTertiary": "#9cd58a",
"mOnTertiary": "#1f2335",
"mError": "#f7768e",
"mOnError": "#1f2335",
"mSurface": "#1f2335",
"mOnSurface": "#a9b1d6",
"mSurfaceVariant": "#2c314a",
"mOnSurfaceVariant": "#8289a6",
"mOutline": "#4b517a",
"mShadow": "#181b2a",
"mHover": "#9cd58a",
"mOnHover": "#1f2335"
},
"light": {
"mPrimary": "#4e70c2",
"mOnPrimary": "#f0f2f7",
"mSecondary": "#85539c",
"mOnSecondary": "#f0f2f7",
"mTertiary": "#4c663b",
"mOnTertiary": "#f0f2f7",
"mError": "#e55561",
"mOnError": "#f0f2f7",
"mSurface": "#f0f2f7",
"mOnSurface": "#4e70c2",
"mSurfaceVariant": "#dbdfea",
"mOnSurfaceVariant": "#6a708a",
"mOutline": "#c8ccd8",
"mShadow": "#a4a8b7",
"mHover": "#4c663b",
"mOnHover": "#f0f2f7"
}
}

View File

@@ -0,0 +1,33 @@
# Colors (TokyoNight-Moon)
[colors.bright]
black = '#545c7e'
blue = '#7a88cf'
cyan = '#7bb0c0'
green = '#9cd58a'
magenta = '#d7729f'
red = '#f7768e'
white = '#a9b1d6'
yellow = '#e6c384'
[colors.cursor]
cursor = '#a9b1d6'
text = '#1f2335'
[colors.normal]
black = '#1f2335'
blue = '#7a88cf'
cyan = '#7bb0c0'
green = '#9cd58a'
magenta = '#d7729f'
red = '#f7768e'
white = '#8289a6'
yellow = '#e6c384'
[colors.primary]
background = '#1f2335'
foreground = '#a9b1d6'
[colors.selection]
background = '#4b517a'
text = '#a9b1d6'

View File

@@ -0,0 +1,33 @@
# Colors (TokyoNight-Moon-Light)
[colors.bright]
black = '#939ab7'
blue = '#5e7bba'
cyan = '#569b9f'
green = '#5e7250'
magenta = '#85539c'
red = '#d26e7a'
white = '#6a708a'
yellow = '#9e8c6b'
[colors.cursor]
cursor = '#4e70c2'
text = '#f0f2f7'
[colors.normal]
black = '#f0f2f7'
blue = '#4e70c2'
cyan = '#569b9f'
green = '#4c663b'
magenta = '#85539c'
red = '#e55561'
white = '#6a708a'
yellow = '#9e8c6b'
[colors.primary]
background = '#f0f2f7'
foreground = '#4e70c2'
[colors.selection]
background = '#c8ccd8'
text = '#4e70c2'

View File

@@ -0,0 +1,22 @@
[colors]
foreground=a9b1d6
background=1f2335
regular0=1f2335
regular1=f7768e
regular2=9cd58a
regular3=e6c384
regular4=7a88cf
regular5=d7729f
regular6=7bb0c0
regular7=8289a6
bright0=545c7e
bright1=f7768e
bright2=9cd58a
bright3=e6c384
bright4=7a88cf
bright5=d7729f
bright6=7bb0c0
bright7=a9b1d6
selection-foreground=a9b1d6
selection-background=4b517a
cursor=1f2335 a9b1d6

View File

@@ -0,0 +1,22 @@
[colors]
foreground=4e70c2
background=f0f2f7
regular0=f0f2f7
regular1=e55561
regular2=4c663b
regular3=9e8c6b
regular4=4e70c2
regular5=85539c
regular6=569b9f
regular7=6a708a
bright0=939ab7
bright1=d26e7a
bright2=5e7250
bright3=9e8c6b
bright4=5e7bba
bright5=85539c
bright6=569b9f
bright7=6a708a
selection-foreground=4e70c2
selection-background=c8ccd8
cursor=f0f2f7 4e70c2

View File

@@ -0,0 +1,22 @@
palette = 0=#1f2335
palette = 1=#f7768e
palette = 2=#9cd58a
palette = 3=#e6c384
palette = 4=#7a88cf
palette = 5=#d7729f
palette = 6=#7bb0c0
palette = 7=#8289a6
palette = 8=#545c7e
palette = 9=#f7768e
palette = 10=#9cd58a
palette = 11=#e6c384
palette = 12=#7a88cf
palette = 13=#d7729f
palette = 14=#7bb0c0
palette = 15=#a9b1d6
background = #1f2335
foreground = #a9b1d6
cursor-color = #a9b1d6
cursor-text = #1f2335
selection-background = #4b517a
selection-foreground = #a9b1d6

View File

@@ -0,0 +1,22 @@
palette = 0=#f0f2f7
palette = 1=#e55561
palette = 2=#4c663b
palette = 3=#9e8c6b
palette = 4=#4e70c2
palette = 5=#85539c
palette = 6=#569b9f
palette = 7=#6a708a
palette = 8=#939ab7
palette = 9=#d26e7a
palette = 10=#5e7250
palette = 11=#9e8c6b
palette = 12=#5e7bba
palette = 13=#85539c
palette = 14=#569b9f
palette = 15=#4e70c2
background = #f0f2f7
foreground = #4e70c2
cursor-color = #4e70c2
cursor-text = #f0f2f7
selection-background = #c8ccd8
selection-foreground = #4e70c2

View File

@@ -0,0 +1,22 @@
color0 #1f2335
color1 #f7768e
color2 #9cd58a
color3 #e6c384
color4 #7a88cf
color5 #d7729f
color6 #7bb0c0
color7 #8289a6
color8 #545c7e
color9 #f7768e
color10 #9cd58a
color11 #e6c384
color12 #7a88cf
color13 #d7729f
color14 #7bb0c0
color15 #a9b1d6
background #1f2335
foreground #a9b1d6
cursor #a9b1d6
cursor_text_color #1f2335
selection_background #4b517a
selection_foreground #a9b1d6

View File

@@ -0,0 +1,22 @@
color0 #f0f2f7
color1 #e55561
color2 #4c663b
color3 #9e8c6b
color4 #4e70c2
color5 #85539c
color6 #569b9f
color7 #6a708a
color8 #939ab7
color9 #d26e7a
color10 #5e7250
color11 #9e8c6b
color12 #5e7bba
color13 #85539c
color14 #569b9f
color15 #4e70c2
background #f0f2f7
foreground #4e70c2
cursor #4e70c2
cursor_text_color #f0f2f7
selection_background #c8ccd8
selection_foreground #4e70c2

View File

@@ -0,0 +1,78 @@
[colors]
ansi = [
"#1f2335",
"#f7768e",
"#9cd58a",
"#e6c384",
"#7a88cf",
"#d7729f",
"#7bb0c0",
"#8289a6",
]
background = "#1f2335"
brights = [
"#545c7e",
"#f7768e",
"#9cd58a",
"#e6c384",
"#7a88cf",
"#d7729f",
"#7bb0c0",
"#a9b1d6",
]
cursor_bg = "#a9b1d6"
cursor_border = "#a9b1d6"
cursor_fg = "#1f2335"
foreground = "#a9b1d6"
selection_bg = "#4b517a"
selection_fg = "#a9b1d6"
[colors.indexed]
[colors.tab_bar]
background = "#1a1e30"
inactive_tab_edge = "#1f2335"
[colors.tab_bar.active_tab]
bg_color = "#1f2335"
fg_color = "#7a88cf"
intensity = "Normal"
italic = false
strikethrough = false
underline = "None"
[colors.tab_bar.inactive_tab]
bg_color = "#1a1e30"
fg_color = "#545c7e"
intensity = "Normal"
italic = false
strikethrough = false
underline = "None"
[colors.tab_bar.inactive_tab_hover]
bg_color = "#1a1e30"
fg_color = "#7a88cf"
intensity = "Normal"
italic = false
strikethrough = false
underline = "None"
[colors.tab_bar.new_tab]
bg_color = "#1a1e30"
fg_color = "#7a88cf"
intensity = "Normal"
italic = false
strikethrough = false
underline = "None"
[colors.tab_bar.new_tab_hover]
bg_color = "#7a88cf"
fg_color = "#1f2335"
intensity = "Normal"
italic = false
strikethrough = false
underline = "None"
[metadata]
author = "folke (Moon Adapted)"
name = "TokyoNight-Moon"

View File

@@ -0,0 +1,78 @@
[colors]
ansi = [
"#f0f2f7",
"#e55561",
"#4c663b",
"#9e8c6b",
"#4e70c2",
"#85539c",
"#569b9f",
"#6a708a",
]
background = "#f0f2f7"
brights = [
"#939ab7",
"#d26e7a",
"#5e7250",
"#9e8c6b",
"#5e7bba",
"#85539c",
"#569b9f",
"#4e70c2",
]
cursor_bg = "#4e70c2"
cursor_border = "#4e70c2"
cursor_fg = "#f0f2f7"
foreground = "#4e70c2"
selection_bg = "#c8ccd8"
selection_fg = "#4e70c2"
[colors.indexed]
[colors.tab_bar]
background = "#dbdfea"
inactive_tab_edge = "#e6eaf3"
[colors.tab_bar.active_tab]
bg_color = "#f0f2f7"
fg_color = "#4e70c2"
intensity = "Normal"
italic = false
strikethrough = false
underline = "None"
[colors.tab_bar.inactive_tab]
bg_color = "#dbdfea"
fg_color = "#939ab7"
intensity = "Normal"
italic = false
strikethrough = false
underline = "None"
[colors.tab_bar.inactive_tab_hover]
bg_color = "#dbdfea"
fg_color = "#4e70c2"
intensity = "Normal"
italic = false
strikethrough = false
underline = "None"
[colors.tab_bar.new_tab]
bg_color = "#dbdfea"
fg_color = "#4e70c2"
intensity = "Normal"
italic = false
strikethrough = false
underline = "None"
[colors.tab_bar.new_tab_hover]
bg_color = "#4e70c2"
fg_color = "#f0f2f7"
intensity = "Normal"
italic = false
strikethrough = false
underline = "None"
[metadata]
author = "folke (Moon Adapted)"
name = "TokyoNight-Moon-Light"

View File

@@ -0,0 +1,3 @@
#auth sufficient pam_fprintd.so max-tries=1
# only uncomment this if you have a fingerprint reader
auth required pam_unix.so

View File

@@ -0,0 +1,18 @@
{
"sources": [
{
"enabled": true,
"name": "Official Noctalia Plugins",
"url": "https://github.com/noctalia-dev/noctalia-plugins"
}
],
"states": {
"privacy-indicator": {
"enabled": true
},
"update-count": {
"enabled": true
}
},
"version": 1
}

View File

@@ -0,0 +1,273 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Services.Pipewire
import qs.Commons
import qs.Modules.Bar.Extras
import qs.Services.UI
import qs.Widgets
Rectangle {
id: root
property var pluginApi: null
property ShellScreen screen
property string widgetId: ""
property string section: ""
readonly property string barPosition: Settings.data.bar.position
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
property bool micActive: false
property bool camActive: false
property bool scrActive: false
property var micApps: []
property var camApps: []
property var scrApps: []
property var cfg: pluginApi?.pluginSettings || ({})
property var defaults: pluginApi?.manifest?.metadata?.defaultSettings || ({})
property bool hideInactive: cfg.hideInactive ?? defaults.hideInactive
property bool removeMargins: cfg.removeMargins ?? defaults.removeMargins
property int iconSpacing: cfg.iconSpacing || Style.marginXS
readonly property color activeColor: Color.mPrimary
readonly property color inactiveColor: Qt.alpha(Color.mOnSurfaceVariant, 0.3)
readonly property color micColor: micActive ? activeColor : inactiveColor
readonly property color camColor: camActive ? activeColor : inactiveColor
readonly property color scrColor: scrActive ? activeColor : inactiveColor
readonly property bool isVisible: !hideInactive || micActive || camActive || scrActive
property real margins: removeMargins ? 0 : Style.marginM * 2
implicitWidth: isVertical ? Style.capsuleHeight : Math.round(layout.implicitWidth + margins)
implicitHeight: isVertical ? Math.round(layout.implicitHeight + margins) : Style.capsuleHeight
Layout.alignment: Qt.AlignVCenter
radius: Style.radiusM
color: Style.capsuleColor
visible: root.isVisible
opacity: root.isVisible ? 1.0 : 0.0
PwObjectTracker {
objects: Pipewire.ready ? Pipewire.nodes.values : []
}
Process {
id: cameraCheckProcess
running: false
command: ["sh", "-c", "for dev in /dev/video*; do [ -e \"$dev\" ] && [ -n \"$(find /proc/[0-9]*/fd/ -lname \"$dev\" 2>/dev/null | head -n1)\" ] && echo \"active\" && exit 0; done; exit 1"]
onExited: (code, status) => {
var isActive = code === 0;
root.camActive = isActive;
if (isActive) {
cameraAppsProcess.running = true;
} else {
root.camApps = [];
}
}
}
Process {
id: cameraAppsProcess
running: false
command: ["sh", "-c", "for dev in /dev/video*; do [ -e \"$dev\" ] && for fd in /proc/[0-9]*/fd/*; do [ -L \"$fd\" ] && [ \"$(readlink \"$fd\" 2>/dev/null)\" = \"$dev\" ] && ps -p \"$(echo \"$fd\" | cut -d/ -f3)\" -o comm= 2>/dev/null; done; done | sort -u | tr '\\n' ',' | sed 's/,$//'"]
onExited: (code, status) => {
if (stdout) {
var appsString = stdout.trim();
var apps = appsString.length > 0 ? appsString.split(',') : [];
root.camApps = apps;
} else {
root.camApps = [];
}
}
}
Timer {
interval: 1000
repeat: true
running: true
triggeredOnStart: true
onTriggered: updatePrivacyState()
}
function hasNodeLinks(node, links) {
for (var i = 0; i < links.length; i++) {
var link = links[i];
if (link && (link.source === node || link.target === node)) {
return true;
}
}
return false;
}
function getAppName(node) {
return node.properties["application.name"] || node.nickname || node.name || "";
}
function updateMicrophoneState(nodes, links) {
var appNames = [];
var isActive = false;
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (!node || !node.isStream || !node.audio || node.isSink) continue;
if (!hasNodeLinks(node, links) || !node.properties) continue;
var mediaClass = node.properties["media.class"] || "";
if (mediaClass === "Stream/Input/Audio") {
if (node.properties["stream.capture.sink"] === "true") {
continue;
}
isActive = true;
var appName = getAppName(node);
if (appName && appNames.indexOf(appName) === -1) {
appNames.push(appName);
}
}
}
root.micActive = isActive;
root.micApps = appNames;
}
function updateCameraState() {
cameraCheckProcess.running = true;
}
function isScreenShareNode(node) {
if (!node.properties) {
return false;
}
var mediaClass = node.properties["media.class"] || "";
if (mediaClass.indexOf("Audio") >= 0) {
return false;
}
if (mediaClass.indexOf("Video") === -1) {
return false;
}
var mediaName = (node.properties["media.name"] || "").toLowerCase();
if (mediaName.match(/^(xdph-streaming|gsr-default|game capture|screen|desktop|display|cast|webrtc|v4l2)/) ||
mediaName === "gsr-default_output" ||
mediaName.match(/screen-cast|screen-capture|desktop-capture|monitor-capture|window-capture|game-capture/i)) {
return true;
}
return false;
}
function updateScreenShareState(nodes, links) {
var appNames = [];
var isActive = false;
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (!node || !hasNodeLinks(node, links) || !node.properties) continue;
if (isScreenShareNode(node)) {
isActive = true;
var appName = getAppName(node);
if (appName && appNames.indexOf(appName) === -1) {
appNames.push(appName);
}
}
}
root.scrActive = isActive;
root.scrApps = appNames;
}
function updatePrivacyState() {
if (!Pipewire.ready) return;
var nodes = Pipewire.nodes.values || [];
var links = Pipewire.links.values || [];
updateMicrophoneState(nodes, links);
updateCameraState();
updateScreenShareState(nodes, links);
}
function buildTooltip() {
var parts = [];
if (micActive && micApps.length > 0) {
parts.push("Mic: " + micApps.join(", "));
}
if (camActive && camApps.length > 0) {
parts.push("Cam: " + camApps.join(", "));
}
if (scrActive && scrApps.length > 0) {
parts.push("Screen sharing: " + scrApps.join(", "));
}
return parts.length > 0 ? parts.join("\n") : "";
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
hoverEnabled: true
onEntered: {
var tooltipText = buildTooltip();
if (tooltipText) {
TooltipService.show(root, tooltipText, BarService.getTooltipDirection());
}
}
onExited: TooltipService.hide()
}
Item {
id: layout
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
implicitWidth: iconsLayout.implicitWidth
implicitHeight: iconsLayout.implicitHeight
GridLayout {
id: iconsLayout
columns: root.isVertical ? 1 : 3
rows: root.isVertical ? 3 : 1
rowSpacing: root.iconSpacing
columnSpacing: root.iconSpacing
NIcon {
visible: micActive || !root.hideInactive
icon: micActive ? "microphone" : "microphone-off"
color: root.micColor
}
NIcon {
visible: camActive || !root.hideInactive
icon: camActive ? "camera" : "camera-off"
color: root.camColor
}
NIcon {
visible: scrActive || !root.hideInactive
icon: scrActive ? "screen-share" : "screen-share-off"
color: root.scrColor
}
}
}
}

View File

@@ -0,0 +1,45 @@
# Privacy Indicator Plugin
A privacy indicator widget that monitors and displays when microphone, camera, or screen sharing is active on your system.
## Features
- **Microphone Monitoring**: Detects active microphone usage via Pipewire
- **Camera Monitoring**: Detects active camera usage by checking `/dev/video*` devices
- **Screen Sharing Detection**: Monitors screen sharing sessions via Pipewire
- **Visual Indicators**: Shows icons that change color based on active state
- Active: Primary color
- Inactive: Semi-transparent variant color
- **App Information**: Tooltip displays which applications are using each resource
- **Adaptive Layout**: Automatically adjusts layout for horizontal or vertical bar positions
## Configuration
Access the plugin settings in Noctalia to configure the following options:
- **Hide Inactive States**: If enabled, microphone, camera, and screen icons are hidden whenever they are inactive. Only active states are shown.
- **RemoveMargins**: If enabled, removes all outer margins of the widget.
- **Icon Spacing**: Controls the horizontal/vertical spacing between the icons.
## Usage
The widget displays three icons in the bar:
- **Microphone**: Shows when any app is using the microphone
- **Camera**: Shows when any app is accessing the camera
- **Screen Share**: Shows when screen sharing is active
Hover over the widget to see a tooltip listing which applications are using each resource.
## Requirements
- Noctalia Shell 3.6.0 or higher
- Pipewire (for microphone and screen sharing detection)
- Access to `/dev/video*` devices (for camera detection)
## Technical Details
- Updates privacy state every second
- Uses Pipewire API to monitor audio/video streams
- Checks `/proc/[0-9]*/fd/` for camera device access
- Detects screen sharing by analyzing Pipewire node properties and media class

View File

@@ -0,0 +1,88 @@
import QtQuick
import QtQuick.Layouts
import qs.Commons
import qs.Widgets
ColumnLayout {
id: root
property var pluginApi: null
property var cfg: pluginApi?.pluginSettings || ({})
property var defaults: pluginApi?.manifest?.metadata?.defaultSettings || ({})
property bool hideInactive: cfg.hideInactive ?? defaults.hideInactive
property bool removeMargins: cfg.removeMargins ?? defaults.removeMargins
property int iconSpacing: cfg.iconSpacing || Style.marginXS
spacing: Style.marginL
Component.onCompleted: {
Logger.i("PrivacyIndicator", "Settings UI loaded");
}
ColumnLayout {
spacing: Style.marginM
Layout.fillWidth: true
NToggle {
label: pluginApi?.tr("settings.hideInactive.label")
description: pluginApi?.tr("settings.hideInactive.desc")
checked: root.hideInactive
onToggled: function (checked) {
root.hideInactive = checked;
}
}
NToggle {
label: pluginApi?.tr("settings.removeMargins.label")
description: pluginApi?.tr("settings.removeMargins.desc")
checked: root.removeMargins
onToggled: function (checked) {
root.removeMargins = checked;
}
}
NComboBox {
label: pluginApi?.tr("settings.iconSpacing.label")
description: pluginApi?.tr("settings.iconSpacing.desc")
model: {
const labels = ["XXS", "XS", "S", "M", "L", "XL"];
const values = [Style.marginXXS, Style.marginXS, Style.marginS, Style.marginM, Style.marginL, Style.marginXL];
const result = [];
for (var i = 0; i < labels.length; ++i) {
const v = values[i];
result.push({
key: v.toFixed(0),
name: `${labels[i]} (${v}px)`
});
}
return result;
}
// INFO: From my understanding, the toFixed(0) shouldn't be needed here and there, but without the
// current key does not show when opening the settings window.
currentKey: root.iconSpacing.toFixed(0)
onSelected: key => root.iconSpacing = key
}
}
function saveSettings() {
if (!pluginApi) {
Logger.e("PrivacyIndicator", "Cannot save settings: pluginApi is null");
return;
}
pluginApi.pluginSettings.hideInactive = root.hideInactive;
pluginApi.pluginSettings.iconSpacing = root.iconSpacing;
pluginApi.pluginSettings.removeMargins = root.removeMargins;
pluginApi.saveSettings();
Logger.i("PrivacyIndicator", "Settings saved successfully");
}
}

View File

@@ -0,0 +1,21 @@
{
"settings": {
"hideInactive": {
"desc": "Mikrofon-, Kamera- und Bildschirmsymbole ausblenden, wenn sie inaktiv sind.",
"label": "Inaktive Zustände ausblenden"
},
"iconSpacing": {
"desc": "Den Abstand zwischen den Symbolen festlegen.",
"label": "Symbolabstand"
},
"removeMargins": {
"desc": "Alle äußeren Ränder des Widgets entfernen.",
"label": "Ränder entfernen"
}
},
"tooltip": {
"cam-on": "Kamera: {apps}",
"mic-on": "Mikrofon: {apps}",
"screen-on": "Bildschirmfreigabe: {apps}"
}
}

View File

@@ -0,0 +1,21 @@
{
"settings": {
"hideInactive": {
"desc": "Hide microphone, camera, and screen icons when there are inactive.",
"label": "Hide inactive states"
},
"iconSpacing": {
"desc": "Set the spacing between the icons.",
"label": "Icon spacing"
},
"removeMargins": {
"desc": "Remove all outer margins of the widget.",
"label": "Remove margins"
}
},
"tooltip": {
"cam-on": "Camera: {apps}",
"mic-on": "Microphone: {apps}",
"screen-on": "Screen sharing: {apps}"
}
}

View File

@@ -0,0 +1,21 @@
{
"settings": {
"hideInactive": {
"desc": "Ocultar los iconos de micrófono, cámara y pantalla cuando estén inactivos.",
"label": "Ocultar estados inactivos"
},
"iconSpacing": {
"desc": "Configurar el espacio entre los iconos.",
"label": "Espaciado de iconos"
},
"removeMargins": {
"desc": "Quita todos los márgenes externos del widget.",
"label": "Quitar márgenes"
}
},
"tooltip": {
"cam-on": "Cámara: {apps}",
"mic-on": "Micrófono: {apps}",
"screen-on": "Compartir pantalla: {apps}"
}
}

View File

@@ -0,0 +1,21 @@
{
"settings": {
"hideInactive": {
"desc": "Masquer les icônes du micro, de la caméra et de lécran lorsquils sont inactifs.",
"label": "Masquer les états inactifs"
},
"iconSpacing": {
"desc": "Définir lespacement entre les icônes.",
"label": "Espacement des icônes"
},
"removeMargins": {
"desc": "Supprime toutes les marges extérieures du widget.",
"label": "Supprimer les marges"
}
},
"tooltip": {
"cam-on": "Caméra: {apps}",
"mic-on": "Microphone: {apps}",
"screen-on": "Partage d'écran: {apps}"
}
}

View File

@@ -0,0 +1,21 @@
{
"settings": {
"hideInactive": {
"desc": "Nascondi le icone di microfono, fotocamera e schermo quando sono inattive.",
"label": "Nascondi stati inattivi"
},
"iconSpacing": {
"desc": "Imposta la distanza tra le icone.",
"label": "Spaziatura delle icone"
},
"removeMargins": {
"desc": "Rimuove tutti i margini esterni del widget.",
"label": "Rimuovi margini"
}
},
"tooltip": {
"cam-on": "Kamera: {apps}",
"mic-on": "Mikrofonoa: {apps}",
"screen-on": "Ekran-partaĝado: {apps}"
}
}

View File

@@ -0,0 +1,21 @@
{
"settings": {
"hideInactive": {
"desc": "マイク・カメラ・画面共有のアイコンを、非アクティブなときは非表示にします。",
"label": "非アクティブ状態を非表示"
},
"iconSpacing": {
"desc": "アイコン同士の間隔を設定します。",
"label": "アイコン間隔"
},
"removeMargins": {
"desc": "ウィジェットの外側の余白をすべて削除します。",
"label": "余白を削除"
}
},
"tooltip": {
"cam-on": "カメラ: {apps}",
"mic-on": "マイク: {apps}",
"screen-on": "画面共有: {apps}"
}
}

View File

@@ -0,0 +1,21 @@
{
"settings": {
"hideInactive": {
"desc": "Verberg de pictogrammen voor microfoon, camera en scherm wanneer ze inactief zijn.",
"label": "Inactieve status verbergen"
},
"iconSpacing": {
"desc": "Stel de afstand tussen de pictogrammen in.",
"label": "Pictogramafstand"
},
"removeMargins": {
"desc": "Verwijdert alle buitenste marges van de widget.",
"label": "Marges verwijderen"
}
},
"tooltip": {
"cam-on": "Camera: {apps}",
"mic-on": "Microfoon: {apps}",
"screen-on": "Schermdeling: {apps}"
}
}

View File

@@ -0,0 +1,21 @@
{
"settings": {
"hideInactive": {
"desc": "Oculta os ícones de microfone, câmera e tela quando estiverem inativos.",
"label": "Ocultar estados inativos"
},
"iconSpacing": {
"desc": "Define o espaçamento entre os ícones.",
"label": "Espaçamento dos ícones"
},
"removeMargins": {
"desc": "Remove todas as margens externas do widget.",
"label": "Remover margens"
}
},
"tooltip": {
"cam-on": "Câmera: {apps}",
"mic-on": "Microfone: {apps}",
"screen-on": "Compartilhamento de tela: {apps}"
}
}

View File

@@ -0,0 +1,21 @@
{
"settings": {
"hideInactive": {
"desc": "Скрывать значки микрофона, камеры и экрана, когда они неактивны.",
"label": "Скрывать неактивные состояния"
},
"iconSpacing": {
"desc": "Задать расстояние между значками.",
"label": "Интервал между значками"
},
"removeMargins": {
"desc": "Удаляет все внешние отступы виджета.",
"label": "Убрать отступы"
}
},
"tooltip": {
"cam-on": "Камера: {apps}",
"mic-on": "Микрофон: {apps}",
"screen-on": "Демонстрация экрана: {apps}"
}
}

View File

@@ -0,0 +1,21 @@
{
"settings": {
"hideInactive": {
"desc": "Mikrofon, kamera ve ekran simgelerini pasif olduklarında gizle.",
"label": "Pasif durumları gizle"
},
"iconSpacing": {
"desc": "Simgeler arasındaki boşluğu ayarla.",
"label": "Simge aralığı"
},
"removeMargins": {
"desc": "Widgetın tüm dış kenar boşluklarını kaldırır.",
"label": "Kenarlıkları kaldır"
}
},
"tooltip": {
"cam-on": "Kamera: {apps}",
"mic-on": "Mikrofon: {apps}",
"screen-on": "Ekran paylaşımı: {apps}"
}
}

View File

@@ -0,0 +1,21 @@
{
"settings": {
"hideInactive": {
"desc": "Приховувати значки мікрофона, камери та екрана, коли вони неактивні.",
"label": "Приховувати неактивні стани"
},
"iconSpacing": {
"desc": "Встановити відстань між значками.",
"label": "Інтервал між значками"
},
"removeMargins": {
"desc": "Видаляє всі зовнішні відступи віджета.",
"label": "Прибрати відступи"
}
},
"tooltip": {
"cam-on": "Камера: {apps}",
"mic-on": "Мікрофон: {apps}",
"screen-on": "Демонстрація екрана: {apps}"
}
}

View File

@@ -0,0 +1,21 @@
{
"settings": {
"hideInactive": {
"desc": "在麦克风、摄像头和屏幕图标处于非活动状态时将其隐藏。",
"label": "隐藏非活动状态"
},
"iconSpacing": {
"desc": "设置图标之间的间距。",
"label": "图标间距"
},
"removeMargins": {
"desc": "移除小部件所有外部边距。",
"label": "移除边距"
}
},
"tooltip": {
"cam-on": "摄像头: {apps}",
"mic-on": "麦克风: {apps}",
"screen-on": "屏幕共享: {apps}"
}
}

View File

@@ -0,0 +1,23 @@
{
"id": "privacy-indicator",
"name": "Privacy Indicator",
"version": "1.0.10",
"minNoctaliaVersion": "3.6.0",
"author": "Noctalia Team <team@noctalia.dev>",
"license": "MIT",
"repository": "https://github.com/noctalia-dev/noctalia-plugins",
"description": "A privacy indicator widget that shows when microphone, camera or screen sharing is active.",
"entryPoints": {
"barWidget": "BarWidget.qml",
"settings": "Settings.qml"
},
"dependencies": {
"plugins": []
},
"metadata": {
"defaultSettings": {
"hideInactive": false,
"removeMargins": false
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -0,0 +1,5 @@
{
"hideInactive": true,
"iconSpacing": 4,
"removeMargins": false
}

View File

@@ -0,0 +1,98 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import qs.Commons
import qs.Widgets
import qs.Services.UI
Rectangle {
id: root
property var pluginApi: null
property ShellScreen screen
property string widgetId: ""
property string section: ""
property bool hovered: false
readonly property string barPosition: Settings.data.bar.position
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
implicitWidth: isVertical ? Style.capsuleHeight : layout.implicitWidth + Style.marginS * 2
implicitHeight: isVertical ? layout.implicitHeight + Style.marginS * 2 : Style.capsuleHeight
color: root.hovered ? Color.mHover : Style.capsuleColor
radius: Style.radiusM
border.color: Style.capsuleBorderColor
border.width: Style.capsuleBorderWidth
property string currentIconName: pluginApi?.pluginSettings?.currentIconName || pluginApi?.manifest?.metadata?.defaultSettings?.currentIconName
property bool hideOnZero: pluginApi?.pluginSettings.hideOnZero || pluginApi?.manifest?.metadata.defaultSettings?.hideOnZero
readonly property bool isVisible: (root.pluginApi?.mainInstance?.updateCount > 0) || !root.hideOnZero
visible: root.isVisible
// also set opacity to zero when invisible as we use opacity to hide the barWidgetLoader
opacity: root.isVisible ? 1.0 : 0.0
//
// ------ Widget ------
//
Item {
id: layout
anchors.centerIn: parent
implicitWidth: grid.implicitWidth
implicitHeight: grid.implicitHeight
GridLayout {
id: grid
columns: root.isVertical ? 1 : 2
rowSpacing: Style.marginS
columnSpacing: Style.marginS
NIcon {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
icon: root.currentIconName
color: root.hovered ? Color.mOnHover : Color.mOnSurface
}
NText {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
text: root.pluginApi?.mainInstance?.updateCount.toString()
color: root.hovered ? Color.mOnHover : Color.mOnSurface
pointSize: Style.fontSizeS
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: root.pluginApi?.mainInstance?.updateCount > 0 ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
root.pluginApi?.mainInstance?.startDoSystemUpdate();
}
onEntered: {
root.hovered = true;
buildTooltip();
}
onExited: {
root.hovered = false;
TooltipService.hide();
}
}
}
function buildTooltip() {
const updateCount = root.pluginApi?.mainInstance?.updateCount
if (updateCount === 0) {
TooltipService.show(root, pluginApi?.tr("tooltip.noUpdatesAvailable"), BarService.getTooltipDirection());
} else {
TooltipService.show(root, pluginApi?.tr("tooltip.updatesAvailable"), BarService.getTooltipDirection());
}
}
}

View File

@@ -0,0 +1,126 @@
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Commons
Item {
id: root
property var pluginApi: null
readonly property url updaterJson: Qt.resolvedUrl("file://" + Settings.configDir + "/plugins/update-count/updaterConfigs.json")
readonly property int minutesToMillis: 60_000
readonly property int updateIntervalMinutes: pluginApi?.pluginSettings.updateIntervalMinutes || pluginApi?.manifest?.metadata.defaultSettings?.updateIntervalMinutes || 30
readonly property string updateTerminalCommand: pluginApi?.pluginSettings.updateTerminalCommand || pluginApi?.manifest?.metadata.defaultSettings?.updateTerminalCommand || ""
property int updateCount: 0
property var updater: null
property var customUpdater: ({
name: "custom",
cmdGetNumUpdates: pluginApi?.pluginSettings.customCmdGetNumUpdates || "",
cmdDoSystemUpdate: pluginApi?.pluginSettings.customCmdDoSystemUpdate || ""
})
//
// ------ Initialization ------
//
property var updaters: []
property int checkIndex: 0
property var current: null
FileView {
id: updaterFile
path: root.updaterJson
onLoaded: {
try {
root.updaters = JSON.parse(updaterFile.text());
root.runAllCmdChecks();
} catch (e) {
Logger.e("UpdateCount", "JSON Error in", root.updaterJson, ":", e);
}
}
}
function runAllCmdChecks() {
if (!root.updaters || root.updaters.length === 0) {
return;
}
root.checkIndex = 0;
root.checkNext();
}
function checkNext() {
if (root.checkIndex >= root.updaters.length) {
startGetNumUpdates();
return;
}
root.current = root.updaters[root.checkIndex++];
cmdCheckProc.command = ["sh", "-c", root.current.cmdCheck];
cmdCheckProc.running = true;
}
Process {
id: cmdCheckProc
onExited: function (exitCode, exitStatus) {
if (exitCode === 0) {
root.updater = root.current
Logger.i("UpdateCount", `Initialization finished. Detected updater: ${root.updater.name}.`);
root.startGetNumUpdates()
} else {
root.checkNext();
}
}
}
//
// ------ Get number of updates ------
//
Timer {
id: timerGetNumUpdates
interval: root.updateIntervalMinutes * root.minutesToMillis
running: true
repeat: true
onTriggered: root.startGetNumUpdates()
}
function startGetNumUpdates() {
const cmd = root.customUpdater.cmdGetNumUpdates || root.updater.cmdGetNumUpdates || "exit 1"
getNumUpdates.command = ["sh", "-c", cmd]
getNumUpdates.running = true;
}
Process {
id: getNumUpdates
stdout: StdioCollector {
onStreamFinished: {
var count = parseInt(text.trim());
root.updateCount = isNaN(count) ? -1 : count;
if (root.updateCount >= 0) {
Logger.i("UpdateCount", `Updates available: ${root.updateCount}`);
} else {
Logger.e("UpdateCount", `getNumUpdates return '${text.trim()}' cannot be parsed into int`);
}
}
}
}
//
// ------ Start update ------
//
function startDoSystemUpdate() {
const cmd = root.customUpdater.cmdDoSystemUpdate || root.updater.cmdDoSystemUpdate || "echo 'No update cmd found.'"
const term = root.updateTerminalCommand.trim();
const fullCmd = (term.indexOf("{}") !== -1) ? term.replace("{}", cmd) : term + " " + cmd;
Quickshell.execDetached(["sh", "-c", fullCmd]);
Logger.i("UpdateCount", `Executed update command: ${fullCmd}`);
}
}

View File

@@ -0,0 +1,52 @@
# Update Count Plugin
A compact Noctalia bar widget that periodically checks for available system updates and displays the current update count. Clicking the widget spawns a terminal to execute the configured system update command.
## Features
- **Periodic Update Checks**: Polls at a configurable interval and updates the displayed count.
- **Package Manager Detection**: Supports common update-check/update flows for supported distros (see Requirements).
- **Click to Update**: Launches a terminal to execute the configured system update command.
- **Custom Commands**: Optional custom commands for both “get number of updates” and “do system update”.
## Installation
This plugin is part of the `noctalia-plugins` repository.
## Configuration
Configure the plugin in Noctalia settings:
- **Hide on Zero Updates**: Hides the widget when the available update count is `0`.
- **Update Check Interval**: Polling interval used for update checks.
- **Icon Identifier / Select Icon**: View and change the currently used icon name.
- **Custom Update Count Command**: Shell command that must output a single integer.
- **Custom System Update Command**: Shell command used to perform the update.
- **Terminal Emulator**: Command used to spawn a terminal for the update action.
- If the value contains `{}`, it will be replaced with the update command.
- If `{}` is not present, the update command is appended.
## Usage
- **Display**: Shows an icon and the current update count.
- **Click**: Spawns the configured terminal command and executes the system update command.
- **Hover**: Shows a tooltip indicating whether updates are available or not.
## Requirements
- **Noctalia Shell**: 3.6.0 or later.
- **Update backend**: one of the supported package managers defined in `updaterConfigs.json` (recommended, but not required).
## Technical Details
- **Updater selection**:
- Built-in update handling is driven by `updaterConfigs.json`, which defines the commands used to:
- determine the number of available updates (`cmdGetNumUpdates`), and
- perform the system update (`cmdDoSystemUpdate`).
- At runtime, the plugin selects the **first available** updater whose required executable checks succeed.
- If no updater matches, the plugin relies on the **custom command** settings.
- **Supported package managers / tools**:
- Arch Linux: `pacman`; `yay`, `paru` (AUR helpers)
- Fedora: `dnf`
- Void Linux: `xbps`

View File

@@ -0,0 +1,193 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Widgets
ColumnLayout {
id: root
property var pluginApi: null
property int updateIntervalMinutes: pluginApi?.pluginSettings?.updateIntervalMinutes || pluginApi?.manifest?.metadata?.defaultSettings?.updateIntervalMinutes
property string updateTerminalCommand: pluginApi?.pluginSettings?.updateTerminalCommand || pluginApi?.manifest?.metadata.defaultSettings?.updateTerminalCommand
property string currentIconName: pluginApi?.pluginSettings?.currentIconName || pluginApi?.manifest?.metadata?.defaultSettings?.currentIconName
property bool hideOnZero: pluginApi?.pluginSettings?.hideOnZero || pluginApi?.manifest?.metadata?.defaultSettings?.hideOnZero
property string customCmdGetNumUpdates: pluginApi?.pluginSettings.customCmdGetNumUpdates || ""
property string customCmdDoSystemUpdate: pluginApi?.pluginSettings.customCmdDoSystemUpdate || ""
spacing: Style.marginL
Component.onCompleted: {
Logger.i("UpdateCount", "Settings UI loaded");
}
//
// ------ General ------
//
NToggle {
id: widgetSwitch
label: pluginApi?.tr("settings.hideWidget.label")
description: pluginApi?.tr("settings.hideWidget.desc")
checked: root.hideOnZero
onToggled: function (checked) {
root.hideOnZero = checked;
}
}
RowLayout {
spacing: Style.marginL
NLabel {
label: pluginApi?.tr("settings.currentIconName.label")
description: pluginApi?.tr("settings.currentIconName.desc")
}
NText {
text: root.currentIconName
color: Settings.data.colorSchemes.darkMode ? Color.mPrimary : Color.mOnPrimary
}
NIcon {
icon: root.currentIconName
color: Settings.data.colorSchemes.darkMode ? Color.mPrimary : Color.mOnPrimary
}
NButton {
text: pluginApi?.tr("settings.changeIcon.label")
onClicked: {
Logger.i("UpdateCount", "Icon selector button clicked.");
changeIcon.open();
}
}
NIconPicker {
id: changeIcon
onIconSelected: function (icon) {
root.currentIconName = icon;
}
}
}
RowLayout {
Layout.fillWidth: true
spacing: Style.marginL
NLabel {
label: pluginApi?.tr("settings.updateInterval.label")
description: pluginApi?.tr("settings.updateInterval.desc")
}
NSlider {
from: 5
to: 300
value: root.updateIntervalMinutes
stepSize: 5
onValueChanged: {
root.updateIntervalMinutes = value;
}
}
NText {
text: root.updateIntervalMinutes.toString().padStart(3, " ") + " minutes"
color: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mOnPrimary
}
}
NDivider {
visible: true
Layout.fillWidth: true
Layout.topMargin: Style.marginL
Layout.bottomMargin: Style.marginL
}
//
// ------ Custom commands ------
//
NTextInput {
label: pluginApi?.tr("settings.customCmdGetNumUpdates.label")
description: pluginApi?.tr("settings.customCmdGetNumUpdates.desc")
placeholderText: pluginApi?.tr("settings.customCmdGetNumUpdates.placeholder")
text: root.customCmdGetNumUpdates
onTextChanged: root.customCmdGetNumUpdates = text
}
NTextInput {
label: pluginApi?.tr("settings.customCmdDoSystemUpdate.label")
description: pluginApi?.tr("settings.customCmdDoSystemUpdate.desc")
placeholderText: pluginApi?.tr("settings.customCmdDoSystemUpdate.placeholder")
text: root.customCmdDoSystemUpdate
onTextChanged: root.customCmdDoSystemUpdate = text
}
NTextInput {
Layout.fillWidth: true
label: pluginApi?.tr("settings.terminal.label")
description: pluginApi?.tr("settings.terminal.desc")
placeholderText: pluginApi?.tr("settings.terminal.placeholder")
text: root.updateTerminalCommand
onTextChanged: root.updateTerminalCommand = text
}
NDivider {
visible: true
Layout.fillWidth: true
Layout.topMargin: Style.marginL
Layout.bottomMargin: Style.marginL
}
//
// ------ Information ------
//
NLabel {
label: pluginApi?.tr("settings.currentCommands.label")
}
ColumnLayout {
RowLayout {
NText {
Layout.fillWidth: true
text: pluginApi?.tr("settings.currentNumUpdatesCmd.label")
color: Settings.data.colorSchemes.darkMode ? Color.mSecondary : Color.mOnSecondary
}
NText {
text: root.customCmdGetNumUpdates || pluginApi?.mainInstance?.updater.cmdGetNumUpdates || "NA"
color: Settings.data.colorSchemes.darkMode ? Color.mTertiary : Color.mOnTertiary
}
}
RowLayout {
NText {
Layout.fillWidth: true
text: pluginApi?.tr("settings.currentUpdateCmd.label")
color: Settings.data.colorSchemes.darkMode ? Color.mSecondary : Color.mOnSecondary
}
NText {
text: root.customCmdDoSystemUpdate || pluginApi?.mainInstance?.updater.cmdDoSystemUpdate || "NA"
color: Settings.data.colorSchemes.darkMode ? Color.mTertiary : Color.mOnTertiary
}
}
}
function saveSettings() {
if (!pluginApi) {
Logger.e("UpdateCount", "Cannot save settings: pluginApi is null");
return;
}
pluginApi.pluginSettings.updateIntervalMinutes = root.updateIntervalMinutes;
pluginApi.pluginSettings.updateTerminalCommand = root.updateTerminalCommand || pluginApi?.manifest?.metadata.defaultSettings?.updateTerminalCommand;
pluginApi.pluginSettings.currentIconName = root.currentIconName;
pluginApi.pluginSettings.hideOnZero = root.hideOnZero;
pluginApi.pluginSettings.customCmdGetNumUpdates = root.customCmdGetNumUpdates;
pluginApi.pluginSettings.customCmdDoSystemUpdate = root.customCmdDoSystemUpdate;
pluginApi.saveSettings();
pluginApi?.mainInstance?.startGetNumUpdates();
Logger.i("UpdateCount", "Settings saved successfully");
pluginApi.closePanel(root.screen);
}
}

View File

@@ -0,0 +1,47 @@
{
"settings": {
"changeIcon": {
"label": "Icon auswählen"
},
"currentCommands": {
"label": "Aktuell konfigurierte Befehle"
},
"currentIconName": {
"desc": "Der aktuell konfigurierte Icon-Name.",
"label": "Icon-Kennung"
},
"currentNumUpdatesCmd": {
"label": "Update-Anzahl"
},
"currentUpdateCmd": {
"label": "System-Update"
},
"customCmdDoSystemUpdate": {
"desc": "Shell-Befehl zum Ausführen des System-Updates.",
"label": "Benutzerdefinierter System-Update-Befehl",
"placeholder": "z. B. yay -Syu"
},
"customCmdGetNumUpdates": {
"desc": "Shell-Befehl, der eine einzelne Ganzzahl als Anzahl verfügbarer Updates ausgeben muss.",
"label": "Benutzerdefinierter Befehl für Update-Anzahl",
"placeholder": "z. B. yay -Quq 2>/dev/null | wc -l"
},
"hideWidget": {
"desc": "Blendet das Widget aus, wenn die Anzahl verfügbarer Updates 0 ist.",
"label": "Bei 0 Updates ausblenden"
},
"terminal": {
"desc": "Terminalbefehl zum Ausführen des System-Update-Befehls. Optional: {} für den Update-Befehl.",
"label": "Terminal-Emulator",
"placeholder": "z. B. foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
},
"updateInterval": {
"desc": "Abfrageintervall für Update-Prüfungen",
"label": "Intervall für Update-Prüfung"
}
},
"tooltip": {
"noUpdatesAvailable": "Keine Updates gefunden",
"updatesAvailable": "Klicken, um den konfigurierten System-Update-Befehl auszuführen"
}
}

View File

@@ -0,0 +1,47 @@
{
"settings": {
"changeIcon": {
"label": "Select Icon"
},
"currentCommands": {
"label": "Currently configured commands"
},
"currentIconName": {
"desc": "Currently configured icon name.",
"label": "Icon Identifier"
},
"currentNumUpdatesCmd": {
"label": "Update count"
},
"currentUpdateCmd": {
"label": "System update"
},
"customCmdDoSystemUpdate": {
"desc": "Shell command used to perform the system update.",
"label": "Custom System Update Command",
"placeholder": "e.g., yay -Syu"
},
"customCmdGetNumUpdates": {
"desc": "Shell command that must output a single integer representing the number of available updates.",
"label": "Custom Update Count Command",
"placeholder": "e.g., yay -Quq 2>/dev/null | wc -l"
},
"hideWidget": {
"desc": "Hide the widget when the available update count is 0.",
"label": "Hide on Zero Updates"
},
"terminal": {
"desc": "Terminal command used to execute the system update command. Optional: {} for update command.",
"label": "Terminal Emulator",
"placeholder": "e.g., foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
},
"updateInterval": {
"desc": "Polling interval for update checks",
"label": "Update Check Interval"
}
},
"tooltip": {
"noUpdatesAvailable": "No updates detected",
"updatesAvailable": "Click to run the configured system update command"
}
}

View File

@@ -0,0 +1,47 @@
{
"settings": {
"changeIcon": {
"label": "Seleccionar icono"
},
"currentCommands": {
"label": "Comandos configurados actualmente"
},
"currentIconName": {
"desc": "Nombre de icono configurado actualmente.",
"label": "Identificador de icono"
},
"currentNumUpdatesCmd": {
"label": "Recuento de actualizaciones"
},
"currentUpdateCmd": {
"label": "Actualización del sistema"
},
"customCmdDoSystemUpdate": {
"desc": "Comando de shell para ejecutar la actualización del sistema.",
"label": "Comando personalizado de actualización",
"placeholder": "p. ej., yay -Syu"
},
"customCmdGetNumUpdates": {
"desc": "Comando de shell que debe imprimir un único entero con el número de actualizaciones disponibles.",
"label": "Comando personalizado de recuento",
"placeholder": "p. ej., yay -Quq 2>/dev/null | wc -l"
},
"hideWidget": {
"desc": "Oculta el widget cuando el número de actualizaciones disponibles es 0.",
"label": "Ocultar con 0 actualizaciones"
},
"terminal": {
"desc": "Comando del terminal usado para ejecutar el comando de actualización del sistema. Opcional: {} para el comando de actualización.",
"label": "Emulador de terminal",
"placeholder": "p. ej., foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
},
"updateInterval": {
"desc": "Intervalo de sondeo para las comprobaciones de actualizaciones",
"label": "Intervalo de comprobación"
}
},
"tooltip": {
"noUpdatesAvailable": "No se detectaron actualizaciones",
"updatesAvailable": "Haz clic para ejecutar el comando de actualización del sistema configurado"
}
}

View File

@@ -0,0 +1,47 @@
{
"settings": {
"changeIcon": {
"label": "Choisir licône"
},
"currentCommands": {
"label": "Commandes actuellement configurées"
},
"currentIconName": {
"desc": "Nom dicône actuellement configuré.",
"label": "Identifiant dicône"
},
"currentNumUpdatesCmd": {
"label": "Nombre de mises à jour"
},
"currentUpdateCmd": {
"label": "Mise à jour système"
},
"customCmdDoSystemUpdate": {
"desc": "Commande shell utilisée pour effectuer la mise à jour du système.",
"label": "Commande personnalisée de mise à jour",
"placeholder": "ex. yay -Syu"
},
"customCmdGetNumUpdates": {
"desc": "Commande shell devant afficher un seul entier correspondant au nombre de mises à jour disponibles.",
"label": "Commande personnalisée de comptage",
"placeholder": "ex. yay -Quq 2>/dev/null | wc -l"
},
"hideWidget": {
"desc": "Masque le widget lorsque le nombre de mises à jour disponibles est 0.",
"label": "Masquer si 0 mise à jour"
},
"terminal": {
"desc": "Commande du terminal utilisée pour exécuter la commande de mise à jour du système. Optionnel : {} pour la commande de mise à jour.",
"label": "Émulateur de terminal",
"placeholder": "ex. foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
},
"updateInterval": {
"desc": "Intervalle de sondage pour les vérifications de mises à jour",
"label": "Intervalle de vérification"
}
},
"tooltip": {
"noUpdatesAvailable": "Aucune mise à jour détectée",
"updatesAvailable": "Cliquer pour exécuter la commande de mise à jour système configurée"
}
}

View File

@@ -0,0 +1,47 @@
{
"settings": {
"changeIcon": {
"label": "Seleziona icona"
},
"currentCommands": {
"label": "Comandi attualmente configurati"
},
"currentIconName": {
"desc": "Nome icona attualmente configurato.",
"label": "Identificatore icona"
},
"currentNumUpdatesCmd": {
"label": "Conteggio aggiornamenti"
},
"currentUpdateCmd": {
"label": "Aggiornamento di sistema"
},
"customCmdDoSystemUpdate": {
"desc": "Comando shell usato per effettuare laggiornamento di sistema.",
"label": "Comando personalizzato di aggiornamento",
"placeholder": "es., yay -Syu"
},
"customCmdGetNumUpdates": {
"desc": "Comando shell che deve stampare un singolo intero che rappresenta il numero di aggiornamenti disponibili.",
"label": "Comando personalizzato per conteggio",
"placeholder": "es., yay -Quq 2>/dev/null | wc -l"
},
"hideWidget": {
"desc": "Nasconde il widget quando il numero di aggiornamenti disponibili è 0.",
"label": "Nascondi con 0 aggiornamenti"
},
"terminal": {
"desc": "Comando del terminale usato per eseguire il comando di aggiornamento di sistema. Opzionale: {} per il comando di aggiornamento.",
"label": "Emulatore di terminale",
"placeholder": "es., foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
},
"updateInterval": {
"desc": "Intervallo di polling per i controlli aggiornamenti",
"label": "Intervallo di verifica"
}
},
"tooltip": {
"noUpdatesAvailable": "Nessun aggiornamento rilevato",
"updatesAvailable": "Clicca per eseguire il comando di aggiornamento di sistema configurato"
}
}

View File

@@ -0,0 +1,47 @@
{
"settings": {
"changeIcon": {
"label": "アイコンを選択"
},
"currentCommands": {
"label": "現在の設定コマンド"
},
"currentIconName": {
"desc": "現在設定されているアイコン名です。",
"label": "アイコン識別子"
},
"currentNumUpdatesCmd": {
"label": "更新件数"
},
"currentUpdateCmd": {
"label": "システム更新"
},
"customCmdDoSystemUpdate": {
"desc": "システム更新を実行するためのシェルコマンドです。",
"label": "システム更新のカスタムコマンド",
"placeholder": "例: yay -Syu"
},
"customCmdGetNumUpdates": {
"desc": "利用可能な更新数を表す整数を 1 つ出力する必要があります。",
"label": "更新件数のカスタムコマンド",
"placeholder": "例: yay -Quq 2>/dev/null | wc -l"
},
"hideWidget": {
"desc": "利用可能な更新数が 0 の場合にウィジェットを非表示にします。",
"label": "更新 0 件で非表示"
},
"terminal": {
"desc": "システム更新コマンドを実行するためのターミナルコマンド。任意: 更新コマンド用に {} を使用します。",
"label": "ターミナルエミュレーター",
"placeholder": "例: foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
},
"updateInterval": {
"desc": "更新チェックのポーリング間隔",
"label": "更新チェック間隔"
}
},
"tooltip": {
"noUpdatesAvailable": "更新は検出されませんでした",
"updatesAvailable": "クリックして設定済みのシステム更新コマンドを実行"
}
}

View File

@@ -0,0 +1,47 @@
{
"settings": {
"changeIcon": {
"label": "Pictogram kiezen"
},
"currentCommands": {
"label": "Huidig geconfigureerde commandos"
},
"currentIconName": {
"desc": "Huidig geconfigureerde pictogramnaam.",
"label": "Pictogram-ID"
},
"currentNumUpdatesCmd": {
"label": "Update-aantal"
},
"currentUpdateCmd": {
"label": "Systeemupdate"
},
"customCmdDoSystemUpdate": {
"desc": "Shell-commando om de systeemupdate uit te voeren.",
"label": "Aangepast systeemupdatecommando",
"placeholder": "bijv. yay -Syu"
},
"customCmdGetNumUpdates": {
"desc": "Shell-commando dat één geheel getal moet uitvoereren met het aantal beschikbare updates.",
"label": "Aangepast commando voor update-aantal",
"placeholder": "bijv. yay -Quq 2>/dev/null | wc -l"
},
"hideWidget": {
"desc": "Verbergt de widget wanneer het aantal beschikbare updates 0 is.",
"label": "Verbergen bij 0 updates"
},
"terminal": {
"desc": "Terminalcommando om het systeemupdatecommando uit te voeren. Optioneel: {} voor het updatecommando.",
"label": "Terminalemulator",
"placeholder": "bijv. foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
},
"updateInterval": {
"desc": "Poll-interval voor updatecontroles",
"label": "Controle-interval"
}
},
"tooltip": {
"noUpdatesAvailable": "Geen updates gevonden",
"updatesAvailable": "Klik om het geconfigureerde systeemupdatecommando uit te voeren"
}
}

View File

@@ -0,0 +1,47 @@
{
"settings": {
"changeIcon": {
"label": "Selecionar ícone"
},
"currentCommands": {
"label": "Comandos atualmente configurados"
},
"currentIconName": {
"desc": "Nome do ícone atualmente configurado.",
"label": "Identificador do ícone"
},
"currentNumUpdatesCmd": {
"label": "Contagem de atualizações"
},
"currentUpdateCmd": {
"label": "Atualização do sistema"
},
"customCmdDoSystemUpdate": {
"desc": "Comando de shell usado para efetuar a atualização do sistema.",
"label": "Comando personalizado de atualização do sistema",
"placeholder": "ex.: yay -Syu"
},
"customCmdGetNumUpdates": {
"desc": "Comando de shell que deve imprimir um único inteiro representando o número de atualizações disponíveis.",
"label": "Comando personalizado para contagem de atualizações",
"placeholder": "ex.: yay -Quq 2>/dev/null | wc -l"
},
"hideWidget": {
"desc": "Oculta o widget quando o número de atualizações disponíveis é 0.",
"label": "Ocultar com 0 atualizações"
},
"terminal": {
"desc": "Comando de terminal usado para executar o comando de atualização do sistema. Opcional: {} para o comando de atualização.",
"label": "Emulador de terminal",
"placeholder": "ex.: foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
},
"updateInterval": {
"desc": "Intervalo de polling para verificações de atualizações",
"label": "Intervalo de verificação de atualizações"
}
},
"tooltip": {
"noUpdatesAvailable": "Nenhuma atualização detetada",
"updatesAvailable": "Clique para executar o comando de atualização do sistema configurado"
}
}

View File

@@ -0,0 +1,47 @@
{
"settings": {
"changeIcon": {
"label": "Выбрать значок"
},
"currentCommands": {
"label": "Текущие настроенные команды"
},
"currentIconName": {
"desc": "Текущее настроенное имя значка.",
"label": "Идентификатор значка"
},
"currentNumUpdatesCmd": {
"label": "Количество обновлений"
},
"currentUpdateCmd": {
"label": "Обновление системы"
},
"customCmdDoSystemUpdate": {
"desc": "Команда оболочки для выполнения обновления системы.",
"label": "Пользовательская команда обновления",
"placeholder": "например: yay -Syu"
},
"customCmdGetNumUpdates": {
"desc": "Команда оболочки должна вывести одно целое число — количество доступных обновлений.",
"label": "Пользовательская команда подсчёта",
"placeholder": "например: yay -Quq 2>/dev/null | wc -l"
},
"hideWidget": {
"desc": "Скрывает виджет, когда количество доступных обновлений равно 0.",
"label": "Скрывать при 0 обновлений"
},
"terminal": {
"desc": "Команда терминала для выполнения команды обновления системы. Необязательно: {} для команды обновления.",
"label": "Эмулятор терминала",
"placeholder": "например: foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
},
"updateInterval": {
"desc": "Интервал опроса для проверки обновлений",
"label": "Интервал проверки"
}
},
"tooltip": {
"noUpdatesAvailable": "Обновления не обнаружены",
"updatesAvailable": "Нажмите, чтобы выполнить настроенную команду обновления системы"
}
}

View File

@@ -0,0 +1,47 @@
{
"settings": {
"changeIcon": {
"label": "Simge seç"
},
"currentCommands": {
"label": "Şu anda yapılandırılmış komutlar"
},
"currentIconName": {
"desc": "Şu anda yapılandırılmış simge adı.",
"label": "Simge tanımlayıcı"
},
"currentNumUpdatesCmd": {
"label": "Güncelleme sayısı"
},
"currentUpdateCmd": {
"label": "Sistem güncellemesi"
},
"customCmdDoSystemUpdate": {
"desc": "Sistem güncellemesini gerçekleştirmek için kullanılan kabuk komutu.",
"label": "Özel sistem güncelleme komutu",
"placeholder": "örn., yay -Syu"
},
"customCmdGetNumUpdates": {
"desc": "Mevcut güncellemelerin sayısını temsil eden tek bir tamsayı çıktılaması gereken kabuk komutu.",
"label": "Özel güncelleme sayısı komutu",
"placeholder": "örn., yay -Quq 2>/dev/null | wc -l"
},
"hideWidget": {
"desc": "Mevcut güncelleme sayısı 0 olduğunda widget'ı gizler.",
"label": "0 güncellemede gizle"
},
"terminal": {
"desc": "Sistem güncelleme komutunu çalıştırmak için kullanılan terminal komutu. İsteğe bağlı: güncelleme komutu için {}.",
"label": "Terminal emülatörü",
"placeholder": "örn., foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
},
"updateInterval": {
"desc": "Güncelleme denetimleri için yoklama aralığı",
"label": "Güncelleme denetim aralığı"
}
},
"tooltip": {
"noUpdatesAvailable": "Güncelleme algılanmadı",
"updatesAvailable": "Yapılandırılmış sistem güncelleme komutunu çalıştırmak için tıklayın"
}
}

View File

@@ -0,0 +1,47 @@
{
"settings": {
"changeIcon": {
"label": "Вибрати іконку"
},
"currentCommands": {
"label": "Поточні налаштовані команди"
},
"currentIconName": {
"desc": "Поточна налаштована назва іконки.",
"label": "Ідентифікатор іконки"
},
"currentNumUpdatesCmd": {
"label": "Кількість оновлень"
},
"currentUpdateCmd": {
"label": "Оновлення системи"
},
"customCmdDoSystemUpdate": {
"desc": "Команда оболонки для виконання оновлення системи.",
"label": "Користувацька команда оновлення системи",
"placeholder": "напр., yay -Syu"
},
"customCmdGetNumUpdates": {
"desc": "Команда оболонки має вивести одне ціле число, що представляє кількість доступних оновлень.",
"label": "Користувацька команда підрахунку оновлень",
"placeholder": "напр., yay -Quq 2>/dev/null | wc -l"
},
"hideWidget": {
"desc": "Приховує віджет, коли кількість доступних оновлень дорівнює 0.",
"label": "Приховувати за 0 оновлень"
},
"terminal": {
"desc": "Команда термінала для виконання команди оновлення системи. Необов’язково: {} для команди оновлення.",
"label": "Емулятор термінала",
"placeholder": "напр., foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
},
"updateInterval": {
"desc": "Інтервал опитування для перевірок оновлень",
"label": "Інтервал перевірки оновлень"
}
},
"tooltip": {
"noUpdatesAvailable": "Оновлень не виявлено",
"updatesAvailable": "Натисніть, щоб запустити налаштовану команду оновлення системи"
}
}

View File

@@ -0,0 +1,47 @@
{
"settings": {
"changeIcon": {
"label": "选择图标"
},
"currentCommands": {
"label": "当前配置的命令"
},
"currentIconName": {
"desc": "当前配置的图标名称。",
"label": "图标标识"
},
"currentNumUpdatesCmd": {
"label": "更新数量"
},
"currentUpdateCmd": {
"label": "系统更新"
},
"customCmdDoSystemUpdate": {
"desc": "用于执行系统更新的 Shell 命令。",
"label": "自定义系统更新命令",
"placeholder": "例如yay -Syu"
},
"customCmdGetNumUpdates": {
"desc": "Shell 命令必须输出一个整数,表示可用更新的数量。",
"label": "自定义更新数量命令",
"placeholder": "例如yay -Quq 2>/dev/null | wc -l"
},
"hideWidget": {
"desc": "当可用更新数为 0 时隐藏该小部件。",
"label": "零更新时隐藏"
},
"terminal": {
"desc": "用于执行系统更新命令的终端命令。可选:使用 {} 代表更新命令占位符。",
"label": "终端模拟器",
"placeholder": "例如foot -ehyprctl dispatch exec '[float] kitty -e {}'"
},
"updateInterval": {
"desc": "更新检查的轮询间隔",
"label": "检查间隔"
}
},
"tooltip": {
"noUpdatesAvailable": "未检测到更新",
"updatesAvailable": "点击运行已配置的系统更新命令"
}
}

View File

@@ -0,0 +1,26 @@
{
"id": "update-count",
"name": "Update Count",
"version": "1.0.5",
"minNoctaliaVersion": "3.6.0",
"author": "BukoMoon",
"license": "GPLv3",
"repository": "https://github.com/noctalia-dev/noctalia-plugins",
"description": "Checks for system updates and shows the update count. Click to run update command in a terminal.",
"entryPoints": {
"main": "Main.qml",
"barWidget": "BarWidget.qml",
"settings": "Settings.qml"
},
"dependencies": {
"plugins": []
},
"metadata": {
"defaultSettings": {
"updateIntervalMinutes": 30,
"updateTerminalCommand": "foot -e",
"currentIconName": "world-download",
"hideOnZero": false
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 KiB

View File

@@ -0,0 +1,8 @@
{
"updateIntervalMinutes": 30,
"updateTerminalCommand": "alacritty -e",
"currentIconName": "world-download",
"hideOnZero": true,
"customCmdGetNumUpdates": "expr $(xbps-install -Mnu 2>&1 | grep -v '^$' | wc -l) + $(flatpak remote-ls --updates | wc -l)",
"customCmdDoSystemUpdate": "~/update.sh"
}

View File

@@ -0,0 +1,32 @@
[
{
"name": "yay",
"cmdCheck": "command -v yay >/dev/null 2>&1",
"cmdGetNumUpdates": "yay -Sy >/dev/null 2>&1; yay -Quq 2>/dev/null | wc -l",
"cmdDoSystemUpdate": "yay -Syu"
},
{
"name": "paru",
"cmdCheck": "command -v paru >/dev/null 2>&1",
"cmdGetNumUpdates": "paru -Sy >/dev/null 2>&1; paru -Quq 2>/dev/null | wc -l",
"cmdDoSystemUpdate": "paru -Syu"
},
{
"name": "pacman",
"cmdCheck": "command -v pacman >/dev/null 2>&1",
"cmdGetNumUpdates": "pacman -Quq 2>/dev/null | wc -l",
"cmdDoSystemUpdate": "sudo pacman -Syu"
},
{
"name": "dnf",
"cmdCheck": "command -v dnf >/dev/null 2>&1",
"cmdGetNumUpdates": "dnf check-update -q | grep -c ^[a-z0-9]",
"cmdDoSystemUpdate": "sudo dnf upgrade"
},
{
"name": "xbps",
"cmdCheck": "command -v xbps-install >/dev/null 2>&1",
"cmdGetNumUpdates": "xbps-install -Mnu 2>&1 | grep -v '^$' | wc -l",
"cmdDoSystemUpdate": "sudo xbps-install -Su"
}
]

View File

@@ -0,0 +1,558 @@
{
"appLauncher": {
"customLaunchPrefix": "",
"customLaunchPrefixEnabled": false,
"enableClipPreview": true,
"enableClipboardHistory": true,
"iconMode": "tabler",
"pinnedExecs": [
],
"position": "center",
"showCategories": true,
"sortByMostUsed": true,
"terminalCommand": "alacritty -e",
"useApp2Unit": false,
"viewMode": "list"
},
"audio": {
"cavaFrameRate": 30,
"externalMixer": "pwvucontrol || pavucontrol",
"mprisBlacklist": [
],
"preferredPlayer": "",
"visualizerType": "linear",
"volumeOverdrive": true,
"volumeStep": 5
},
"bar": {
"capsuleOpacity": 1,
"density": "comfortable",
"exclusive": true,
"floating": false,
"marginHorizontal": 0.25,
"marginVertical": 0.25,
"monitors": [
],
"outerCorners": false,
"position": "top",
"showCapsule": true,
"showOutline": false,
"transparent": false,
"widgets": {
"center": [
{
"hideMode": "hidden",
"hideWhenIdle": false,
"id": "MediaMini",
"maxWidth": 250,
"scrollingMode": "hover",
"showAlbumArt": true,
"showArtistFirst": true,
"showProgressRing": true,
"showVisualizer": true,
"useFixedWidth": false,
"visualizerType": "linear"
}
],
"left": [
{
"hideMode": "alwaysExpanded",
"icon": "rocket",
"id": "CustomButton",
"leftClickExec": "qs -c noctalia-shell ipc call launcher toggle",
"leftClickUpdateText": false,
"maxTextLength": {
"horizontal": 10,
"vertical": 10
},
"middleClickExec": "",
"middleClickUpdateText": false,
"parseJson": false,
"rightClickExec": "",
"rightClickUpdateText": false,
"showIcon": true,
"textCollapse": "",
"textCommand": "",
"textIntervalMs": 3000,
"textStream": false,
"wheelDownExec": "",
"wheelDownUpdateText": false,
"wheelExec": "",
"wheelMode": "unified",
"wheelUpExec": "",
"wheelUpUpdateText": false,
"wheelUpdateText": false
},
{
"characterCount": 10,
"colorizeIcons": false,
"enableScrollWheel": true,
"followFocusedScreen": false,
"hideUnoccupied": true,
"id": "Workspace",
"labelMode": "name",
"showApplications": false,
"showLabelsOnlyWhenOccupied": true
},
{
"customFont": "",
"formatHorizontal": "HH:mm ddd, MMM dd",
"formatVertical": "HH mm - dd MM",
"id": "Clock",
"useCustomFont": false,
"usePrimaryColor": false
},
{
"id": "plugin:update-count"
},
{
"diskPath": "/",
"id": "SystemMonitor",
"showCpuTemp": true,
"showCpuUsage": true,
"showDiskUsage": false,
"showGpuTemp": false,
"showMemoryAsPercent": false,
"showMemoryUsage": true,
"showNetworkStats": false,
"usePrimaryColor": false
},
{
"colorizeIcons": true,
"hideMode": "hidden",
"iconScale": 1,
"id": "Taskbar",
"maxTaskbarWidth": 40,
"onlyActiveWorkspaces": false,
"onlySameOutput": true,
"showPinnedApps": true,
"showTitle": false,
"smartWidth": true,
"titleWidth": 120
}
],
"right": [
{
"id": "ScreenRecorder"
},
{
"blacklist": [
],
"colorizeIcons": false,
"drawerEnabled": true,
"hidePassive": false,
"id": "Tray",
"pinned": [
]
},
{
"hideWhenZero": true,
"id": "NotificationHistory",
"showUnreadBadge": true
},
{
"deviceNativePath": "",
"displayMode": "onhover",
"hideIfNotDetected": true,
"id": "Battery",
"showNoctaliaPerformance": false,
"showPowerProfiles": false,
"warningThreshold": 30
},
{
"displayMode": "onhover",
"id": "Volume"
},
{
"displayMode": "onhover",
"id": "Brightness"
},
{
"id": "plugin:privacy-indicator"
},
{
"colorizeDistroLogo": false,
"colorizeSystemIcon": "none",
"customIconPath": "/home/aiden/Pictures/Icons/Void_Linux_logo-notext.png",
"enableColorization": false,
"icon": "noctalia",
"id": "ControlCenter",
"useDistroLogo": false
}
]
}
},
"brightness": {
"brightnessStep": 5,
"enableDdcSupport": false,
"enforceMinimum": true
},
"calendar": {
"cards": [
{
"enabled": true,
"id": "calendar-header-card"
},
{
"enabled": true,
"id": "calendar-month-card"
},
{
"enabled": true,
"id": "timer-card"
},
{
"enabled": true,
"id": "weather-card"
}
]
},
"colorSchemes": {
"darkMode": true,
"generateTemplatesForPredefined": true,
"manualSunrise": "06:30",
"manualSunset": "18:30",
"matugenSchemeType": "scheme-fruit-salad",
"predefinedScheme": "Catppuccin",
"schedulingMode": "off",
"useWallpaperColors": false
},
"controlCenter": {
"cards": [
{
"enabled": true,
"id": "profile-card"
},
{
"enabled": true,
"id": "shortcuts-card"
},
{
"enabled": true,
"id": "audio-card"
},
{
"enabled": true,
"id": "weather-card"
},
{
"enabled": true,
"id": "media-sysmon-card"
},
{
"enabled": false,
"id": "brightness-card"
}
],
"position": "close_to_bar_button",
"shortcuts": {
"left": [
{
"id": "WiFi"
},
{
"id": "Bluetooth"
},
{
"id": "ScreenRecorder"
},
{
"id": "WallpaperSelector"
}
],
"right": [
{
"id": "Notifications"
},
{
"id": "PowerProfile"
},
{
"id": "KeepAwake"
},
{
"id": "NightLight"
}
]
}
},
"desktopWidgets": {
"enabled": false,
"gridSnap": true,
"monitorWidgets": [
{
"name": "DP-3",
"widgets": [
]
},
{
"name": "DP-5",
"widgets": [
]
}
]
},
"dock": {
"animationSpeed": 1,
"backgroundOpacity": 1,
"colorizeIcons": true,
"deadOpacity": 0.6,
"displayMode": "auto_hide",
"enabled": false,
"floatingRatio": 1,
"inactiveIndicators": false,
"monitors": [
],
"onlySameOutput": true,
"pinnedApps": [
],
"pinnedStatic": false,
"size": 1
},
"general": {
"allowPanelsOnScreenWithoutBar": true,
"animationDisabled": false,
"animationSpeed": 1,
"avatarImage": "/home/aiden/.face",
"boxRadiusRatio": 1,
"compactLockScreen": false,
"dimmerOpacity": 0,
"enableShadows": true,
"forceBlackScreenCorners": false,
"iRadiusRatio": 1,
"language": "",
"lockOnSuspend": true,
"radiusRatio": 1,
"scaleRatio": 1,
"screenRadiusRatio": 1,
"shadowDirection": "bottom_right",
"shadowOffsetX": 2,
"shadowOffsetY": 3,
"showHibernateOnLockScreen": false,
"showScreenCorners": false,
"showSessionButtonsOnLockScreen": true
},
"hooks": {
"darkModeChange": "",
"enabled": false,
"performanceModeDisabled": "",
"performanceModeEnabled": "",
"screenLock": "",
"screenUnlock": "",
"wallpaperChange": ""
},
"location": {
"analogClockInCalendar": false,
"firstDayOfWeek": -1,
"name": "Winnipeg, MB",
"showCalendarEvents": true,
"showCalendarWeather": true,
"showWeekNumberInCalendar": false,
"use12hourFormat": false,
"useFahrenheit": false,
"weatherEnabled": true,
"weatherShowEffects": true
},
"network": {
"wifiEnabled": true
},
"nightLight": {
"autoSchedule": false,
"dayTemp": "6500",
"enabled": true,
"forced": false,
"manualSunrise": "07:30",
"manualSunset": "21:00",
"nightTemp": "4140"
},
"notifications": {
"backgroundOpacity": 1,
"criticalUrgencyDuration": 15,
"enableKeyboardLayoutToast": true,
"enabled": true,
"location": "top_right",
"lowUrgencyDuration": 3,
"monitors": [
"DP-3"
],
"normalUrgencyDuration": 8,
"overlayLayer": true,
"respectExpireTimeout": false,
"sounds": {
"criticalSoundFile": "",
"enabled": false,
"excludedApps": "discord,firefox,chrome,chromium,edge",
"lowSoundFile": "",
"normalSoundFile": "",
"separateSounds": false,
"volume": 0.5
}
},
"osd": {
"autoHideMs": 2000,
"backgroundOpacity": 1,
"enabled": true,
"enabledTypes": [
0,
1,
2
],
"location": "top_right",
"monitors": [
],
"overlayLayer": true
},
"screenRecorder": {
"audioCodec": "opus",
"audioSource": "default_output",
"colorRange": "limited",
"directory": "/home/aiden/Videos",
"frameRate": 60,
"quality": "very_high",
"showCursor": true,
"videoCodec": "h264",
"videoSource": "portal"
},
"sessionMenu": {
"countdownDuration": 10000,
"enableCountdown": true,
"largeButtonsStyle": false,
"position": "center",
"powerOptions": [
{
"action": "lock",
"command": "",
"countdownEnabled": false,
"enabled": true
},
{
"action": "suspend",
"command": "",
"countdownEnabled": true,
"enabled": true
},
{
"action": "hibernate",
"command": "",
"countdownEnabled": true,
"enabled": false
},
{
"action": "reboot",
"command": "",
"countdownEnabled": true,
"enabled": true
},
{
"action": "logout",
"command": "",
"countdownEnabled": true,
"enabled": true
},
{
"action": "shutdown",
"command": "",
"countdownEnabled": true,
"enabled": true
}
],
"showHeader": true
},
"settingsVersion": 32,
"systemMonitor": {
"cpuCriticalThreshold": 90,
"cpuPollingInterval": 3000,
"cpuWarningThreshold": 80,
"criticalColor": "",
"diskCriticalThreshold": 90,
"diskPollingInterval": 3000,
"diskWarningThreshold": 80,
"enableDgpuMonitoring": false,
"gpuCriticalThreshold": 90,
"gpuPollingInterval": 3000,
"gpuWarningThreshold": 80,
"memCriticalThreshold": 90,
"memPollingInterval": 3000,
"memWarningThreshold": 80,
"networkPollingInterval": 3000,
"tempCriticalThreshold": 90,
"tempPollingInterval": 3000,
"tempWarningThreshold": 80,
"useCustomColors": false,
"warningColor": ""
},
"templates": {
"alacritty": false,
"cava": false,
"code": false,
"discord": false,
"emacs": false,
"enableUserTemplates": false,
"foot": false,
"fuzzel": false,
"ghostty": false,
"gtk": true,
"helix": false,
"hyprland": false,
"kcolorscheme": true,
"kitty": false,
"mango": false,
"niri": true,
"pywalfox": false,
"qt": true,
"spicetify": false,
"telegram": false,
"vicinae": false,
"walker": false,
"wezterm": false,
"yazi": false,
"zed": false
},
"ui": {
"bluetoothDetailsViewMode": "grid",
"bluetoothHideUnnamedDevices": false,
"fontDefault": "Sans Serif",
"fontDefaultScale": 1,
"fontFixed": "monospace",
"fontFixedScale": 1,
"panelBackgroundOpacity": 0.5,
"panelsAttachedToBar": true,
"settingsPanelMode": "centered",
"tooltipsEnabled": true,
"wifiDetailsViewMode": "grid"
},
"wallpaper": {
"directory": "/home/aiden/Pictures/Wallpapers",
"enableMultiMonitorDirectories": true,
"enabled": true,
"fillColor": "#000000",
"fillMode": "crop",
"hideWallpaperFilenames": false,
"monitorDirectories": [
{
"directory": "/home/aiden/Pictures/Wallpapers",
"name": "DP-5",
"wallpaper": ""
}
],
"overviewEnabled": false,
"panelPosition": "follow_bar",
"randomEnabled": true,
"randomIntervalSec": 600,
"recursiveSearch": false,
"setWallpaperOnAllMonitors": false,
"transitionDuration": 1500,
"transitionEdgeSmoothness": 0.05,
"transitionType": "random",
"useWallhaven": false,
"wallhavenCategories": "111",
"wallhavenOrder": "desc",
"wallhavenPurity": "100",
"wallhavenQuery": "",
"wallhavenRatios": "",
"wallhavenResolutionHeight": "",
"wallhavenResolutionMode": "atleast",
"wallhavenResolutionWidth": "",
"wallhavenSorting": "relevance"
}
}

View File

@@ -0,0 +1,17 @@
[config]
[templates]
# User-defined templates
# Add your custom templates below
# Example:
# [templates.myapp]
# input_path = "~/.config/noctalia/templates/myapp.css"
# output_path = "~/.config/myapp/theme.css"
# post_hook = "myapp --reload-theme"
# Remove this section and add your own templates
#[templates.placeholder]
#input_path = "/home/aiden/.config/quickshell/noctalia-shell/Assets/MatugenTemplates/noctalia.json"
#output_path = "/home/aiden/.cache/noctalia/placeholder.json"