mirror of
https://github.com/Theaninova/TheaninovOS.git
synced 2025-12-15 13:06:22 +00:00
update system
This commit is contained in:
34
overlays/asztal/widget/settings/Group.ts
Normal file
34
overlays/asztal/widget/settings/Group.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import icons from "lib/icons"
|
||||
import Row from "./Row"
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export default (title: string, ...rows: ReturnType<typeof Row<any>>[]) => Widget.Box(
|
||||
{
|
||||
class_name: "group",
|
||||
vertical: true,
|
||||
},
|
||||
Widget.Box([
|
||||
Widget.Label({
|
||||
hpack: "start",
|
||||
vpack: "end",
|
||||
class_name: "group-title",
|
||||
label: title,
|
||||
setup: w => Utils.idle(() => w.visible = !!title),
|
||||
}),
|
||||
title ? Widget.Button({
|
||||
hexpand: true,
|
||||
hpack: "end",
|
||||
child: Widget.Icon(icons.ui.refresh),
|
||||
class_name: "group-reset",
|
||||
sensitive: Utils.merge(
|
||||
rows.map(({ attribute: { opt } }) => opt.bind().as(v => v !== opt.initial)),
|
||||
(...values) => values.some(b => b),
|
||||
),
|
||||
on_clicked: () => rows.forEach(row => row.attribute.opt.reset()),
|
||||
}) : Widget.Box(),
|
||||
]),
|
||||
Widget.Box({
|
||||
vertical: true,
|
||||
children: rows,
|
||||
}),
|
||||
)
|
||||
19
overlays/asztal/widget/settings/Page.ts
Normal file
19
overlays/asztal/widget/settings/Page.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import Group from "./Group"
|
||||
|
||||
export default <T>(
|
||||
name: string,
|
||||
icon: string,
|
||||
...groups: ReturnType<typeof Group<T>>[]
|
||||
) => Widget.Box({
|
||||
class_name: "page",
|
||||
attribute: { name, icon },
|
||||
child: Widget.Scrollable({
|
||||
css: "min-height: 300px;",
|
||||
child: Widget.Box({
|
||||
class_name: "page-content",
|
||||
vexpand: true,
|
||||
vertical: true,
|
||||
children: groups,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
55
overlays/asztal/widget/settings/Row.ts
Normal file
55
overlays/asztal/widget/settings/Row.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { Opt } from "lib/option"
|
||||
import Setter from "./Setter"
|
||||
import icons from "lib/icons"
|
||||
|
||||
export type RowProps<T> = {
|
||||
opt: Opt<T>
|
||||
title: string
|
||||
note?: string
|
||||
type?:
|
||||
| "number"
|
||||
| "color"
|
||||
| "float"
|
||||
| "object"
|
||||
| "string"
|
||||
| "enum"
|
||||
| "boolean"
|
||||
| "img"
|
||||
| "font"
|
||||
enums?: string[]
|
||||
max?: number
|
||||
min?: number
|
||||
}
|
||||
|
||||
export default <T>(props: RowProps<T>) => Widget.Box(
|
||||
{
|
||||
attribute: { opt: props.opt },
|
||||
class_name: "row",
|
||||
tooltip_text: props.note ? `note: ${props.note}` : "",
|
||||
},
|
||||
Widget.Box(
|
||||
{ vertical: true, vpack: "center" },
|
||||
Widget.Label({
|
||||
xalign: 0,
|
||||
class_name: "row-title",
|
||||
label: props.title,
|
||||
}),
|
||||
Widget.Label({
|
||||
xalign: 0,
|
||||
class_name: "id",
|
||||
label: props.opt.id,
|
||||
}),
|
||||
),
|
||||
Widget.Box({ hexpand: true }),
|
||||
Widget.Box(
|
||||
{ vpack: "center" },
|
||||
Setter(props),
|
||||
),
|
||||
Widget.Button({
|
||||
vpack: "center",
|
||||
class_name: "reset",
|
||||
child: Widget.Icon(icons.ui.refresh),
|
||||
on_clicked: () => props.opt.reset(),
|
||||
sensitive: props.opt.bind().as(v => v !== props.opt.initial),
|
||||
}),
|
||||
)
|
||||
93
overlays/asztal/widget/settings/Setter.ts
Normal file
93
overlays/asztal/widget/settings/Setter.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { type RowProps } from "./Row"
|
||||
import { Opt } from "lib/option"
|
||||
import icons from "lib/icons"
|
||||
import Gdk from "gi://Gdk"
|
||||
|
||||
function EnumSetter(opt: Opt<string>, values: string[]) {
|
||||
const lbl = Widget.Label({ label: opt.bind().as(v => `${v}`) })
|
||||
const step = (dir: 1 | -1) => {
|
||||
const i = values.findIndex(i => i === lbl.label)
|
||||
opt.setValue(dir > 0
|
||||
? i + dir > values.length - 1 ? values[0] : values[i + dir]
|
||||
: i + dir < 0 ? values[values.length - 1] : values[i + dir],
|
||||
)
|
||||
}
|
||||
const next = Widget.Button({
|
||||
child: Widget.Icon(icons.ui.arrow.right),
|
||||
on_clicked: () => step(+1),
|
||||
})
|
||||
const prev = Widget.Button({
|
||||
child: Widget.Icon(icons.ui.arrow.left),
|
||||
on_clicked: () => step(-1),
|
||||
})
|
||||
return Widget.Box({
|
||||
class_name: "enum-setter",
|
||||
children: [lbl, prev, next],
|
||||
})
|
||||
}
|
||||
|
||||
export default function Setter<T>({
|
||||
opt,
|
||||
type = typeof opt.value as RowProps<T>["type"],
|
||||
enums,
|
||||
max = 1000,
|
||||
min = 0,
|
||||
}: RowProps<T>) {
|
||||
switch (type) {
|
||||
case "number": return Widget.SpinButton({
|
||||
setup(self) {
|
||||
self.set_range(min, max)
|
||||
self.set_increments(1, 5)
|
||||
self.on("value-changed", () => opt.value = self.value as T)
|
||||
self.hook(opt, () => self.value = opt.value as number)
|
||||
},
|
||||
})
|
||||
|
||||
case "float":
|
||||
case "object": return Widget.Entry({
|
||||
on_accept: self => opt.value = JSON.parse(self.text || ""),
|
||||
setup: self => self.hook(opt, () => self.text = JSON.stringify(opt.value)),
|
||||
})
|
||||
|
||||
case "string": return Widget.Entry({
|
||||
on_accept: self => opt.value = self.text as T,
|
||||
setup: self => self.hook(opt, () => self.text = opt.value as string),
|
||||
})
|
||||
|
||||
case "enum": return EnumSetter(opt as unknown as Opt<string>, enums!)
|
||||
case "boolean": return Widget.Switch()
|
||||
.on("notify::active", self => opt.value = self.active as T)
|
||||
.hook(opt, self => self.active = opt.value as boolean)
|
||||
|
||||
case "img": return Widget.FileChooserButton({
|
||||
on_file_set: ({ uri }) => { opt.value = uri!.replace("file://", "") as T },
|
||||
})
|
||||
|
||||
case "font": return Widget.FontButton({
|
||||
show_size: false,
|
||||
use_size: false,
|
||||
setup: self => self
|
||||
.hook(opt, () => self.font = opt.value as string)
|
||||
.on("font-set", ({ font }) => opt.value = font!
|
||||
.split(" ").slice(0, -1).join(" ") as T),
|
||||
})
|
||||
|
||||
case "color": return Widget.ColorButton()
|
||||
.hook(opt, self => {
|
||||
const rgba = new Gdk.RGBA()
|
||||
rgba.parse(opt.value as string)
|
||||
self.rgba = rgba
|
||||
})
|
||||
.on("color-set", ({ rgba: { red, green, blue } }) => {
|
||||
const hex = (n: number) => {
|
||||
const c = Math.floor(255 * n).toString(16)
|
||||
return c.length === 1 ? `0${c}` : c
|
||||
}
|
||||
opt.value = `#${hex(red)}${hex(green)}${hex(blue)}` as T
|
||||
})
|
||||
|
||||
default: return Widget.Label({
|
||||
label: `no setter with type ${type}`,
|
||||
})
|
||||
}
|
||||
}
|
||||
63
overlays/asztal/widget/settings/SettingsDialog.ts
Normal file
63
overlays/asztal/widget/settings/SettingsDialog.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import RegularWindow from "widget/RegularWindow"
|
||||
import layout from "./layout"
|
||||
import icons from "lib/icons"
|
||||
import options from "options"
|
||||
|
||||
const current = Variable(layout[0].attribute.name)
|
||||
|
||||
const Header = () => Widget.CenterBox({
|
||||
class_name: "header",
|
||||
start_widget: Widget.Button({
|
||||
class_name: "reset",
|
||||
on_clicked: options.reset,
|
||||
hpack: "start",
|
||||
vpack: "start",
|
||||
child: Widget.Icon(icons.ui.refresh),
|
||||
tooltip_text: "Reset",
|
||||
}),
|
||||
center_widget: Widget.Box({
|
||||
class_name: "pager horizontal",
|
||||
children: layout.map(({ attribute: { name, icon } }) => Widget.Button({
|
||||
xalign: 0,
|
||||
class_name: current.bind().as(v => `${v === name ? "active" : ""}`),
|
||||
on_clicked: () => current.value = name,
|
||||
child: Widget.Box([
|
||||
Widget.Icon(icon),
|
||||
Widget.Label(name),
|
||||
]),
|
||||
})),
|
||||
}),
|
||||
end_widget: Widget.Button({
|
||||
class_name: "close",
|
||||
hpack: "end",
|
||||
vpack: "start",
|
||||
child: Widget.Icon(icons.ui.close),
|
||||
on_clicked: () => App.closeWindow("settings-dialog"),
|
||||
}),
|
||||
})
|
||||
|
||||
const PagesStack = () => Widget.Stack({
|
||||
transition: "slide_left_right",
|
||||
children: layout.reduce((obj, page) => ({ ...obj, [page.attribute.name]: page }), {}),
|
||||
shown: current.bind() as never,
|
||||
})
|
||||
|
||||
export default () => RegularWindow({
|
||||
name: "settings-dialog",
|
||||
class_name: "settings-dialog",
|
||||
title: "Settings",
|
||||
setup(win) {
|
||||
win.on("delete-event", () => {
|
||||
win.hide()
|
||||
return true
|
||||
})
|
||||
win.set_default_size(500, 600)
|
||||
},
|
||||
child: Widget.Box({
|
||||
vertical: true,
|
||||
children: [
|
||||
Header(),
|
||||
PagesStack(),
|
||||
],
|
||||
}),
|
||||
})
|
||||
31
overlays/asztal/widget/settings/Wallpaper.ts
Normal file
31
overlays/asztal/widget/settings/Wallpaper.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import wallpaper from "service/wallpaper"
|
||||
|
||||
export default () => Widget.Box(
|
||||
{ class_name: "row wallpaper" },
|
||||
Widget.Box(
|
||||
{ vertical: true },
|
||||
Widget.Label({
|
||||
xalign: 0,
|
||||
class_name: "row-title",
|
||||
label: "Wallpaper",
|
||||
vpack: "start",
|
||||
}),
|
||||
Widget.Button({
|
||||
on_clicked: wallpaper.random,
|
||||
label: "Random",
|
||||
}),
|
||||
Widget.FileChooserButton({
|
||||
on_file_set: ({ uri }) => wallpaper.set(uri!.replace("file://", "")),
|
||||
}),
|
||||
),
|
||||
Widget.Box({ hexpand: true }),
|
||||
Widget.Box({
|
||||
class_name: "preview",
|
||||
css: wallpaper.bind("wallpaper").as(wp => `
|
||||
min-height: 120px;
|
||||
min-width: 200px;
|
||||
background-image: url('${wp}');
|
||||
background-size: cover;
|
||||
`),
|
||||
}),
|
||||
)
|
||||
147
overlays/asztal/widget/settings/layout.ts
Normal file
147
overlays/asztal/widget/settings/layout.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
/* eslint-disable max-len */
|
||||
import Row from "./Row"
|
||||
import Group from "./Group"
|
||||
import Page from "./Page"
|
||||
import Wallpaper from "./Wallpaper"
|
||||
import options from "options"
|
||||
import icons from "lib/icons"
|
||||
|
||||
const {
|
||||
autotheme: at,
|
||||
font,
|
||||
theme,
|
||||
bar: b,
|
||||
launcher: l,
|
||||
overview: ov,
|
||||
powermenu: pm,
|
||||
quicksettings: qs,
|
||||
osd,
|
||||
hyprland: h,
|
||||
} = options
|
||||
|
||||
const {
|
||||
dark,
|
||||
light,
|
||||
blur,
|
||||
scheme,
|
||||
padding,
|
||||
spacing,
|
||||
radius,
|
||||
shadows,
|
||||
widget,
|
||||
border,
|
||||
} = theme
|
||||
|
||||
export default [
|
||||
Page("Theme", icons.ui.themes,
|
||||
Group("",
|
||||
Wallpaper() as ReturnType<typeof Row>,
|
||||
Row({ opt: at, title: "Auto Generate Color Scheme" }),
|
||||
Row({ opt: scheme, title: "Color Scheme", type: "enum", enums: ["dark", "light"] }),
|
||||
),
|
||||
Group("Dark Colors",
|
||||
Row({ opt: dark.bg, title: "Background", type: "color" }),
|
||||
Row({ opt: dark.fg, title: "Foreground", type: "color" }),
|
||||
Row({ opt: dark.primary.bg, title: "Primary", type: "color" }),
|
||||
Row({ opt: dark.primary.fg, title: "On Primary", type: "color" }),
|
||||
Row({ opt: dark.error.bg, title: "Error", type: "color" }),
|
||||
Row({ opt: dark.error.fg, title: "On Error", type: "color" }),
|
||||
Row({ opt: dark.widget, title: "Widget", type: "color" }),
|
||||
Row({ opt: dark.border, title: "Border", type: "color" }),
|
||||
),
|
||||
Group("Light Colors",
|
||||
Row({ opt: light.bg, title: "Background", type: "color" }),
|
||||
Row({ opt: light.fg, title: "Foreground", type: "color" }),
|
||||
Row({ opt: light.primary.bg, title: "Primary", type: "color" }),
|
||||
Row({ opt: light.primary.fg, title: "On Primary", type: "color" }),
|
||||
Row({ opt: light.error.bg, title: "Error", type: "color" }),
|
||||
Row({ opt: light.error.fg, title: "On Error", type: "color" }),
|
||||
Row({ opt: light.widget, title: "Widget", type: "color" }),
|
||||
Row({ opt: light.border, title: "Border", type: "color" }),
|
||||
),
|
||||
Group("Theme",
|
||||
Row({ opt: shadows, title: "Shadows" }),
|
||||
Row({ opt: widget.opacity, title: "Widget Opacity", max: 100 }),
|
||||
Row({ opt: border.opacity, title: "Border Opacity", max: 100 }),
|
||||
Row({ opt: border.width, title: "Border Width" }),
|
||||
Row({ opt: blur, title: "Blur", note: "0 to disable", max: 70 }),
|
||||
),
|
||||
Group("UI",
|
||||
Row({ opt: padding, title: "Padding" }),
|
||||
Row({ opt: spacing, title: "Spacing" }),
|
||||
Row({ opt: radius, title: "Roundness" }),
|
||||
Row({ opt: font.size, title: "Font Size" }),
|
||||
Row({ opt: font.name, title: "Font Name", type: "font" }),
|
||||
),
|
||||
),
|
||||
Page("Bar", icons.ui.toolbars,
|
||||
Group("General",
|
||||
Row({ opt: b.flatButtons, title: "Flat Buttons" }),
|
||||
Row({ opt: b.position, title: "Position", type: "enum", enums: ["top", "bottom"] }),
|
||||
Row({ opt: b.corners, title: "Corners" }),
|
||||
),
|
||||
Group("Launcher",
|
||||
Row({ opt: b.launcher.icon.icon, title: "Icon" }),
|
||||
Row({ opt: b.launcher.icon.colored, title: "Colored Icon" }),
|
||||
Row({ opt: b.launcher.label.label, title: "Label" }),
|
||||
Row({ opt: b.launcher.label.colored, title: "Colored Label" }),
|
||||
),
|
||||
Group("Workspaces",
|
||||
Row({ opt: b.workspaces.workspaces, title: "Number of Workspaces", note: "0 to make it dynamic" }),
|
||||
),
|
||||
Group("Taskbar",
|
||||
Row({ opt: b.taskbar.iconSize, title: "Icon Size" }),
|
||||
Row({ opt: b.taskbar.monochrome, title: "Monochrome" }),
|
||||
Row({ opt: b.taskbar.exclusive, title: "Exclusive to workspaces" }),
|
||||
),
|
||||
Group("Date",
|
||||
Row({ opt: b.date.format, title: "Date Format" }),
|
||||
),
|
||||
Group("Media",
|
||||
Row({ opt: b.media.monochrome, title: "Monochrome" }),
|
||||
Row({ opt: b.media.preferred, title: "Preferred Player" }),
|
||||
Row({ opt: b.media.direction, title: "Slide Direction", type: "enum", enums: ["left", "right"] }),
|
||||
Row({ opt: b.media.format, title: "Format of the Label" }),
|
||||
Row({ opt: b.media.length, title: "Max Length of Label" }),
|
||||
),
|
||||
Group("Battery",
|
||||
Row({ opt: b.battery.bar, title: "Style", type: "enum", enums: ["hidden", "regular", "whole"] }),
|
||||
Row({ opt: b.battery.blocks, title: "Number of Blocks" }),
|
||||
Row({ opt: b.battery.width, title: "Width of Bar" }),
|
||||
Row({ opt: b.battery.charging, title: "Charging Color", type: "color" }),
|
||||
),
|
||||
Group("Powermenu",
|
||||
Row({ opt: b.powermenu.monochrome, title: "Monochrome" }),
|
||||
),
|
||||
),
|
||||
Page("General", icons.ui.settings,
|
||||
Group("Hyprland",
|
||||
Row({ opt: h.gapsWhenOnly, title: "Gaps When Only" }),
|
||||
),
|
||||
Group("Launcher",
|
||||
Row({ opt: l.width, title: "Width" }),
|
||||
Row({ opt: l.apps.iconSize, title: "Icon Size" }),
|
||||
Row({ opt: l.apps.max, title: "Max Items" }),
|
||||
),
|
||||
Group("Overview",
|
||||
Row({ opt: ov.scale, title: "Scale", max: 100 }),
|
||||
Row({ opt: ov.workspaces, title: "Workspaces", max: 11, note: "set this to 0 to make it dynamic" }),
|
||||
Row({ opt: ov.monochromeIcon, title: "Monochrome Icons" }),
|
||||
),
|
||||
Group("Powermenu",
|
||||
Row({ opt: pm.layout, title: "Layout", type: "enum", enums: ["box", "line"] }),
|
||||
Row({ opt: pm.labels, title: "Show Labels" }),
|
||||
),
|
||||
Group("Quicksettings",
|
||||
Row({ opt: qs.avatar.image, title: "Avatar", type: "img" }),
|
||||
Row({ opt: qs.avatar.size, title: "Avatar Size" }),
|
||||
Row({ opt: qs.media.monochromeIcon, title: "Media Monochrome Icons" }),
|
||||
Row({ opt: qs.media.coverSize, title: "Media Cover Art Size" }),
|
||||
),
|
||||
Group("On Screen Indicator",
|
||||
Row({ opt: osd.progress.vertical, title: "Vertical" }),
|
||||
Row({ opt: osd.progress.pack.h, title: "Horizontal Alignment", type: "enum", enums: ["start", "center", "end"] }),
|
||||
Row({ opt: osd.progress.pack.v, title: "Vertical Alignment", type: "enum", enums: ["start", "center", "end"] }),
|
||||
),
|
||||
),
|
||||
] as const
|
||||
144
overlays/asztal/widget/settings/settingsdialog.scss
Normal file
144
overlays/asztal/widget/settings/settingsdialog.scss
Normal file
@@ -0,0 +1,144 @@
|
||||
window.settings-dialog {
|
||||
background-color: $bg;
|
||||
color: $fg;
|
||||
|
||||
.header {
|
||||
.pager {
|
||||
@include spacing(.5);
|
||||
}
|
||||
|
||||
padding: $padding;
|
||||
|
||||
button {
|
||||
@include button;
|
||||
font-weight: bold;
|
||||
padding: $padding*.5 $padding;
|
||||
|
||||
box {
|
||||
@include spacing($spacing: .3em);
|
||||
}
|
||||
}
|
||||
|
||||
button.close {
|
||||
padding: $padding * .5;
|
||||
}
|
||||
|
||||
button.reset {
|
||||
@include button($flat: true);
|
||||
padding: $padding*.5;
|
||||
}
|
||||
}
|
||||
|
||||
.page {
|
||||
@include scrollable($top: true);
|
||||
|
||||
.page-content {
|
||||
padding: $padding*2;
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.group {
|
||||
.group-title {
|
||||
color: $primary-bg;
|
||||
margin-bottom: $spacing*.5;
|
||||
}
|
||||
|
||||
.group-reset {
|
||||
@include button($flat: true);
|
||||
margin: $spacing * .5;
|
||||
padding: $padding * .5;
|
||||
|
||||
&:disabled {
|
||||
color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top: $spacing;
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
background-color: $widget-bg;
|
||||
padding: $padding;
|
||||
border: $border;
|
||||
border-top: none;
|
||||
|
||||
&:first-child {
|
||||
border-radius: $radius $radius 0 0;
|
||||
border: $border;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-radius: 0 0 $radius $radius;
|
||||
}
|
||||
|
||||
&:first-child:last-child {
|
||||
border-radius: $radius;
|
||||
border: $border;
|
||||
}
|
||||
|
||||
button.reset {
|
||||
margin-left: $spacing;
|
||||
}
|
||||
|
||||
label.id,
|
||||
label.note {
|
||||
color: transparentize($fg, .4)
|
||||
}
|
||||
|
||||
entry,
|
||||
button {
|
||||
@include button;
|
||||
padding: $padding;
|
||||
}
|
||||
|
||||
switch {
|
||||
@include switch;
|
||||
}
|
||||
|
||||
spinbutton {
|
||||
@include unset;
|
||||
|
||||
entry {
|
||||
border-radius: $radius 0 0 $radius;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:last-child {
|
||||
border-radius: 0 $radius $radius 0;
|
||||
}
|
||||
}
|
||||
|
||||
.enum-setter {
|
||||
label {
|
||||
background-color: $widget-bg;
|
||||
border: $border;
|
||||
padding: 0 $padding;
|
||||
border-radius: $radius 0 0 $radius;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:last-child {
|
||||
border-radius: 0 $radius $radius 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.wallpaper {
|
||||
button {
|
||||
margin-top: $spacing * .5;
|
||||
}
|
||||
|
||||
.preview {
|
||||
border-radius: $radius;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user