async parsing + tex caching

This commit is contained in:
2026-08-26 02:06:10 +02:00
parent e18875a752
commit 3946541f87
32 changed files with 2730 additions and 489 deletions
+9 -13
View File
@@ -44,7 +44,7 @@ WidgetBase {
}
required property GridLayout loader
required property Wrapper popouts
readonly property real size: horizontal ? timeText.contentWidth + Tokens.padding.small * 2 : verticalColumn.implicitHeight + Tokens.padding.small * 2
readonly property real size: horizontal ? timeText.contentWidth + Tokens.padding.medium * 2 : verticalColumn.implicitHeight + Tokens.padding.medium * 2
required property PersistentProperties visibilities
color: visibilities.dashboard ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer
@@ -57,14 +57,13 @@ WidgetBase {
anchors.centerIn: parent
color: root.contentColor
font.family: Config.appearance.font.family.mono // qmllint disable incompatible-type
font.family: Config.appearance.font.family.clock // qmllint disable incompatible-type
height: implicitHeight
text: Time.dateStr
visible: root.horizontal
Behavior on color {
CAnim {
}
CAnim {}
}
}
@@ -84,12 +83,11 @@ WidgetBase {
Layout.alignment: Qt.AlignHCenter
color: root.contentColor
font.family: Config.appearance.font.family.mono // qmllint disable incompatible-type
font.family: Config.appearance.font.family.clock // qmllint disable incompatible-type
text: Qt.formatDateTime(Time.date, modelData)
Behavior on color {
CAnim {
}
CAnim {}
}
}
}
@@ -114,7 +112,7 @@ WidgetBase {
Layout.alignment: Qt.AlignHCenter
color: root.contentColor
font.family: Config.appearance.font.family.mono // qmllint disable incompatible-type
font.family: Config.appearance.font.family.clock // qmllint disable incompatible-type
text: {
if (modelData.includes("h"))
return Time.hourStr;
@@ -126,8 +124,7 @@ WidgetBase {
}
Behavior on color {
CAnim {
}
CAnim {}
}
}
}
@@ -135,13 +132,12 @@ WidgetBase {
CustomText {
Layout.alignment: Qt.AlignHCenter
color: root.contentColor
font.family: Config.appearance.font.family.mono // qmllint disable incompatible-type
font.family: Config.appearance.font.family.clock // qmllint disable incompatible-type
text: Qt.formatDateTime(Time.date, "AP")
visible: Config.services.useTwelveHourClock && root.formatParts.timeTokens.length > 0
Behavior on color {
CAnim {
}
CAnim {}
}
}
}
@@ -177,7 +177,14 @@ Item {
sendIcon.icon: "arrow_upward"
sendIcon.padding: Tokens.padding.extraSmall
onAccepted: root.send(text)
Keys.onPressed: e => {
if (e.key == Qt.Key_Return) {
if (!(e.modifiers & Qt.ShiftModifier)) {
root.send(text);
e.accepted = true;
}
}
}
onSendPressed: root.send(text)
}
}
@@ -3,7 +3,7 @@ import ZShell.Config
import qs.Components
import qs.Services
TextFieldBase {
TextAreaBase {
id: root
readonly property alias bg: bg
@@ -15,7 +15,7 @@ TextFieldBase {
leftPadding: Tokens.padding.extraLarge
rightPadding: sendIcon.width + sendIcon.anchors.rightMargin + Tokens.spacing.small
topPadding: Tokens.padding.large
wrapMode: TextFieldBase.Wrap
wrapMode: TextAreaBase.Wrap
background: CustomRect {
id: bg
@@ -1,4 +1,5 @@
import QtQuick
import QtQuick.Shapes
import QtQuick.Layouts
import Quickshell
import ZShell.Config
@@ -12,57 +13,69 @@ CustomClippingRect {
required property string language
required property string code
property bool copied: false
property color codeColor: Colors.palette.m3onSurfaceVariant
property color codeBackgroundColor: Colors.palette.m3surfaceContainerLow
property color codeBackgroundColor: Colors.palette.m3surfaceContainerHigh
property color codeHeaderColor: Colors.palette.m3outline
property color codeAccentColor: Colors.palette.m3primary
// Highlighter spans for the current code; refreshed when the code or
// its language changes.
// its language changes. Highlighting runs off the GUI thread; the
// token drops results that arrive after the code already changed.
property var codeSpans: []
property int highlightToken: 0
function refresh() {
codeSpans = CodeHighlighter.highlight(root.code, root.language);
const token = ++root.highlightToken;
codeSpans = [];
CodeHighlighter.highlight(root.code, root.language, root, token);
}
function onHighlightSpans(token, spans) {
if (token !== root.highlightToken)
return;
codeSpans = spans;
}
function roleColor(kind) {
var s = CodeColors.active;
switch (kind) {
case "comment":
return Colors.palette.m3outline;
return s.comment;
case "string":
return Colors.palette.m3tertiary;
return s.string;
case "string.key":
return Colors.palette.m3secondary;
return s.stringKey;
case "number":
case "constant":
return Colors.palette.m3tertiaryFixed;
return s.number;
case "keyword":
return root.codeAccentColor;
return s.keyword;
case "type":
return Colors.palette.m3secondary;
return s.type;
case "function":
return s.functions;
case "method":
return Colors.palette.m3onSurface;
return s.method ?? s.functions;
case "macro":
return s.macro;
case "preproc":
return Colors.palette.m3secondaryContainer;
return s.preproc ?? s.macro;
case "operator":
return s.operator ?? s.normal;
case "property":
return root.codeColor;
return s.property ?? s.normal;
case "label":
return s.label;
case "attribute":
return Colors.palette.m3tertiaryFixedDim;
return s.attribute ?? s.label;
default:
return root.codeColor;
return s.normal;
}
}
function escapeHtml(text) {
function escapeHtml(text): string {
return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
}
// Wraps the code in <font color> tags following the highlighter spans.
function highlightedHtml(code, spans) {
function highlightedHtml(code, spans): string {
let out;
if (!spans.length) {
out = escapeHtml(code);
@@ -79,37 +92,17 @@ CustomClippingRect {
if (pos < code.length)
out += escapeHtml(code.slice(pos));
}
// RichText collapses HTML whitespace: break newlines, and protect
// line-leading indentation with nbsp (internal spaces stay normal
// so long lines can still wrap).
return out
.replace(/(^|\n)[ \t]+/g, ws => ws.replace(/[ \t]/g, "&nbsp;"))
.replace(/\n/g, "<br>");
return out.replace(/(^|\n)[ \t]+/g, ws => ws.replace(/[ \t]/g, "&nbsp;")).replace(/\n/g, "<br>");
}
implicitWidth: headerRow.implicitWidth + headerRow.anchors.leftMargin + headerRow.anchors.rightMargin
implicitHeight: headerRow.anchors.topMargin + headerRow.implicitHeight + codeText.implicitHeight + codeText.anchors.margins * 2
implicitHeight: headerRow.anchors.topMargin + headerRow.implicitHeight + codeRect.implicitHeight + codeRect.anchors.margins + codeRect.anchors.topMargin
color: root.codeBackgroundColor
radius: Tokens.rounding.medium
onLanguageChanged: refresh()
onCodeChanged: refresh()
CustomText {
id: codeText
anchors.left: parent.left
anchors.top: headerRow.bottom
anchors.right: parent.right
anchors.margins: Tokens.padding.small
color: root.codeColor
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.small
textFormat: Text.RichText
text: root.highlightedHtml(root.code, root.codeSpans)
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
}
RowLayout {
id: headerRow
@@ -121,11 +114,74 @@ CustomClippingRect {
anchors.rightMargin: Tokens.padding.small
spacing: Tokens.spacing.small
Item {
id: iconItem
readonly property string iconPath: CodeIcons.path(root.language)
Layout.fillHeight: true
implicitWidth: height
Shape {
id: shape
anchors.centerIn: parent
visible: iconItem.iconPath !== ""
preferredRendererType: Shape.CurveRenderer
scale: Math.min(langText.implicitHeight / height, langText.implicitHeight / width)
ShapePath {
strokeColor: "transparent"
fillColor: Colors.palette.m3tertiary
fillRule: ShapePath.WindingFill
PathSvg {
path: iconItem.iconPath
}
}
}
Shape {
id: fallbackShape
anchors.centerIn: parent
anchors.verticalCenterOffset: -1
visible: iconItem.iconPath === ""
preferredRendererType: Shape.CurveRenderer
scale: Math.min(langText.implicitHeight / height, langText.implicitHeight / width)
ShapePath {
strokeColor: Colors.palette.m3tertiary
strokeWidth: 16
capStyle: ShapePath.RoundCap
joinStyle: ShapePath.RoundJoin
fillColor: "transparent"
PathSvg {
path: "M 40 64 L 112 128 L 40 192"
}
}
ShapePath {
strokeColor: Colors.palette.m3tertiary
strokeWidth: 16
capStyle: ShapePath.RoundCap
fillColor: "transparent"
PathSvg {
path: "M 120 192 L 216 192"
}
}
}
}
CustomText {
id: langText
Layout.alignment: Qt.AlignVCenter
color: root.codeHeaderColor
font.pointSize: Tokens.font.size.small
text: root.language
text: CodeIcons.name(root.language)
visible: root.language.length > 0
}
@@ -137,6 +193,7 @@ CustomClippingRect {
icon: root.copied ? "check" : "content_copy"
inactiveColor: "transparent"
inactiveOnColor: root.codeHeaderColor
label.animate: true
type: IconButton.Text
onClicked: {
@@ -154,4 +211,40 @@ CustomClippingRect {
}
}
}
CustomRect {
id: codeRect
anchors.left: parent.left
anchors.top: headerRow.bottom
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.topMargin: Tokens.padding.small
radius: root.radius - anchors.margins
anchors.margins: Tokens.padding.extraSmall
implicitWidth: codeText.implicitWidth + codeFlick.anchors.margins * 2
implicitHeight: codeText.implicitHeight + codeFlick.anchors.margins * 2
color: CodeColors.active.bg
Flickable {
id: codeFlick
anchors.fill: parent
anchors.margins: Tokens.padding.small
CustomScrollBar.horizontal: CustomScrollBar {
flickable: codeFlick
}
TextAreaBase.flickable: TextAreaBase {
id: codeText
color: CodeColors.active.normal
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.small
textFormat: Text.RichText
text: root.highlightedHtml(root.code, root.codeSpans)
readOnly: true
}
}
}
}
@@ -0,0 +1,231 @@
pragma Singleton
import Quickshell
import Quickshell.Io
import QtQuick
import ZShell.Config
Singleton {
id: root
readonly property JsonObject schemes: JsonObject {
readonly property Scheme oneDark: Scheme {
comment: "#5c6370"
string: "#98c379"
stringKey: "#e06c75"
number: "#d19a66"
keyword: "#c678dd"
type: "#e5c07b"
functions: "#61afef"
method: "#61afef"
macro: "#98c379"
preproc: "#abb2bf"
operator: "#abb2bf"
property: "#abb2bf"
label: "#e06c75"
attribute: "#d19a66"
bg: "#282c34"
normal: "#abb2bf"
}
readonly property Scheme nord: Scheme {
comment: "#4c566a"
string: "#a3be8c"
stringKey: "#ebcb8b"
number: "#b48ead"
keyword: "#81a1c1"
type: "#8fbcbb"
functions: "#88c0d0"
method: "#88c0d0"
macro: "#5e81ac"
preproc: "#5e81ac"
operator: "#81a1c1"
property: "#d8dee9"
label: "#d08770"
attribute: "#d8dee9"
bg: "#2e3440"
normal: "#d8dee9"
}
readonly property Scheme dracula: Scheme {
comment: "#6272a4"
string: "#f1fa8c"
stringKey: "#f8f8f2"
number: "#ffb86c"
keyword: "#ff79c6"
type: "#8be9fd"
functions: "#50fa7b"
method: "#50fa7b"
macro: "#ff79c6"
preproc: "#ff79c6"
operator: "#f8f8f2"
property: "#f8f8f2"
label: "#6272a4"
attribute: "#8be9fd"
bg: "#282a36"
normal: "#f8f8f2"
}
readonly property Scheme githubDark: Scheme {
comment: "#8b949e"
string: "#a5d6ff"
stringKey: "#79c0ff"
number: "#79c0ff"
keyword: "#ff7b72"
type: "#ffa657"
functions: "#d2a8ff"
method: "#d2a8ff"
macro: "#ff7b72"
preproc: "#79c0ff"
operator: "#ff7b72"
property: "#79c0ff"
label: "#7ee787"
attribute: "#7ee787"
bg: "#0d1117"
normal: "#c9d1d9"
}
readonly property Scheme solarizedDark: Scheme {
comment: "#586e75"
string: "#2aa198"
stringKey: "#268bd2"
number: "#2aa198"
keyword: "#859900"
type: "#b58900"
functions: "#268bd2"
method: "#268bd2"
macro: "#cb4b16"
preproc: "#cb4b16"
operator: "#859900"
property: "#268bd2"
label: "#6c71c4"
attribute: "#657b83"
bg: "#002b36"
normal: "#839496"
}
readonly property Scheme monokai: Scheme {
comment: "#75715e"
string: "#e6db74"
stringKey: "#f8f8f2"
number: "#ae81ff"
keyword: "#f92672"
type: "#a6e22e"
functions: "#a6e22e"
method: "#a6e22e"
macro: "#a6e22e"
preproc: "#f92672"
operator: "#f92672"
property: "#fda5ff"
label: "#f92672"
attribute: "#a6e22e"
bg: "#272822"
normal: "#f8f8f2"
}
readonly property Scheme gruvboxDark: Scheme {
comment: "#928374"
string: "#b8bb26"
stringKey: "#ebdbb2"
number: "#d3869b"
keyword: "#fb4934"
type: "#fabd2f"
functions: "#b8bb26"
method: "#b8bb26"
macro: "#8ec07c"
preproc: "#8ec07c"
operator: "#ebdbb2"
property: "#83a598"
label: "#fb4934"
attribute: "#8ec07c"
bg: "#1d2021"
normal: "#ebdbb2"
}
readonly property Scheme catppuccinMocha: Scheme {
comment: "#9399b2"
string: "#a6e3a1"
stringKey: "#b4befe"
number: "#fab387"
keyword: "#cba6f7"
type: "#f9e2af"
functions: "#89b4fa"
method: "#89b4fa"
macro: "#cba6f7"
preproc: "#f5c2e7"
operator: "#89dceb"
property: "#b4befe"
label: "#74c7ec"
attribute: "#f9e2af"
bg: "#1e1e2e"
normal: "#cdd6f4"
}
readonly property Scheme tokyoNight: Scheme {
comment: "#565f89"
string: "#9ece6a"
stringKey: "#73daca"
number: "#ff9e64"
keyword: "#9d7cd8"
type: "#2ac3de"
functions: "#7aa2f7"
method: "#7aa2f7"
macro: "#7dcfff"
preproc: "#7dcfff"
operator: "#89ddff"
property: "#73daca"
label: "#7aa2f7"
attribute: "#73daca"
bg: "#1a1b26"
normal: "#c0caf5"
}
readonly property Scheme ayuDark: Scheme {
comment: "#5a6673"
string: "#aad94c"
stringKey: "#aad94c"
number: "#d2a6ff"
keyword: "#ff8f40"
type: "#59c2ff"
functions: "#ffb454"
method: "#ffb454"
macro: "#59c2ff"
preproc: "#ff8f40"
operator: "#f29668"
property: "#f07178"
label: "#59c2ff"
attribute: "#ffb454"
bg: "#0a0e14"
normal: "#bfbdb6"
}
readonly property Scheme palenight: Scheme {
comment: "#697098"
string: "#c3e88d"
stringKey: "#82b1ff"
number: "#f78c6c"
keyword: "#ff5370"
type: "#ffcb6b"
functions: "#82b1ff"
method: "#82b1ff"
macro: "#c792ea"
preproc: "#ffcb6b"
operator: "#89ddff"
property: "#c3e88d"
label: "#c792ea"
attribute: "#ffcb6b"
bg: "#292d3e"
normal: "#bfc7d5"
}
}
readonly property var active: schemes[Config.llm.appearance.scheme]
component Scheme: JsonObject {
property color comment: "#697098"
property color string: "#c3e88d"
property color stringKey: "#82b1ff"
property color number: "#f78c6c"
property color keyword: "#ff5370"
property color type: "#ffcb6b"
property color functions: "#82b1ff"
property color method: "#82b1ff"
property color macro: "#c792ea"
property color preproc: "#ffcb6b"
property color operator: "#89ddff"
property color property: "#c3e88d"
property color label: "#c792ea"
property color attribute: "#ffcb6b"
property color bg: "#292d3e"
property color normal: "#bfc7d5"
}
}
File diff suppressed because one or more lines are too long
@@ -30,7 +30,7 @@ Item {
radius: Tokens.rounding.medium
color: root.isUser ? Colors.palette.m3primary : Colors.palette.m3surfaceContainer
implicitWidth: root.isUser ? Math.min(msgText.implicitWidth + Tokens.padding.medium * 2, root.contentMaxWidth) : root.contentMaxWidth
implicitHeight: root.isUser ? msgText.contentHeight + Tokens.padding.medium * 2 : blocks.implicitHeight + Tokens.padding.medium * 2
implicitHeight: root.isUser ? msgText.contentHeight + Tokens.padding.medium * 2 : blocks.implicitHeight + blocks.anchors.topMargin * 2
anchors.right: root.isUser ? parent.right : undefined
// User messages stay a plain editable text field.
@@ -92,10 +92,10 @@ Item {
id: blocks
visible: !root.isUser
anchors.topMargin: Tokens.padding.medium
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: Tokens.padding.medium
blocks: root.segment.markdown
}
}
@@ -29,6 +29,7 @@ Column {
language: modelData.language
code: modelData.code
anchors.right: parent.right
anchors.margins: Tokens.spacing.small
anchors.left: parent.left
}
}
@@ -42,6 +43,7 @@ Column {
latex: modelData.latex
anchors.right: parent.right
anchors.left: parent.left
anchors.margins: Tokens.padding.medium
}
}
@@ -54,6 +56,7 @@ Column {
color: Colors.palette.m3onSurface
anchors.right: parent.right
anchors.left: parent.left
anchors.margins: Tokens.padding.medium
text: modelData.text
textFormat: Text.MarkdownText
font.bold: true
@@ -77,6 +80,7 @@ Column {
color: Colors.palette.m3onSurface
anchors.right: parent.right
anchors.left: parent.left
anchors.margins: Tokens.padding.medium
text: modelData.text
textFormat: Text.MarkdownText
font.pointSize: Tokens.font.size.smaller
+12 -7
View File
@@ -17,11 +17,14 @@ Item {
property int horizontalContentMargin
required property string icon
required property string label
property string subtext: ""
property bool open
property real openHeight: Math.min(rootParent.height * 0.8, 600)
property real openWidth: Math.min(rootParent.width * 0.8, 400)
required property Item rootParent
property bool separateContent
property bool first: false
property bool last: false
signal accepted
signal cancelled
@@ -44,8 +47,7 @@ Item {
color: root.open ? Colors.palette.m3surfaceContainerHighest : Colors.tPalette.m3surfaceContainer
Behavior on color {
CAnim {
}
CAnim {}
}
}
@@ -131,12 +133,13 @@ Item {
id: dialogBg
anchors.fill: parent
bottomLeftRadius: Tokens.rounding.largeIncreased
bottomRightRadius: Tokens.rounding.largeIncreased
bottomLeftRadius: root.last ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall
bottomRightRadius: root.last ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall
topRightRadius: root.first ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall
topLeftRadius: root.first ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall
deformScale: 0
group: blobGroup
opacity: blobGroup.color.a * (root.enabled ? 1 : 0.5)
radius: Tokens.rounding.extraSmall
}
RowButton {
@@ -145,9 +148,11 @@ Item {
anchors.left: parent.left
anchors.right: parent.right
color: "transparent"
height: Math.min(implicitHeight, parent.height) // Clamp to parent height due to overshoot anim
height: Math.min(implicitHeight, parent.height)
icon: root.icon
last: true
subtext: root.subtext
last: root.last
first: root.first
text: root.label
transform: Matrix4x4 {
+29 -46
View File
@@ -11,6 +11,7 @@ import qs.Modules.Settings.Pages.Audio
import qs.Modules.Settings.Pages.Apps
import qs.Modules.Settings.Pages.Panels
import qs.Modules.Settings.Pages.Panels.Bar
import qs.Modules.Settings.Pages.Panels.Sidebar
import qs.Modules.Settings.Pages.Services
import qs.Services
@@ -23,13 +24,11 @@ QtObject {
// Wallpaper & style
StackPage {
Component {
WallpaperPage {
}
WallpaperPage {}
}
Component {
WallpaperSelect {
}
WallpaperSelect {}
}
}
},
@@ -37,32 +36,27 @@ QtObject {
// Screenshot
StackPage {
Component {
ScreenshotPage {
}
ScreenshotPage {}
}
}
},
// Connectivity
Component {
PlaceholderComp {
}
PlaceholderComp {}
},
Component {
PlaceholderComp {
}
PlaceholderComp {}
},
Component {
// Audio
StackPage {
Component {
AudioPage {
}
AudioPage {}
}
Component {
AppVolumes {
}
AppVolumes {}
}
}
},
@@ -71,49 +65,45 @@ QtObject {
Component {
StackPage {
Component {
PanelsPage {
}
PanelsPage {}
}
Component {
BarPanel {
}
BarPanel {}
}
Component {
DashboardPanel {
}
DashboardPanel {}
}
Component {
ResourcesPanel {
}
ResourcesPanel {}
}
Component {
LauncherPanel {
}
LauncherPanel {}
}
Component {
SidebarPanel {
}
SidebarPanel {}
}
// Bar sub pages
Component {
BarTray {
}
BarTray {}
}
Component {
BarStatusIcons {
}
BarStatusIcons {}
}
Component {
BarClock {
}
BarClock {}
}
// Sidebar sub pages
Component {
SidebarLlm {}
}
}
},
@@ -122,18 +112,15 @@ QtObject {
Component {
StackPage {
Component {
AppsPage {
}
AppsPage {}
}
Component {
AllApps {
}
AllApps {}
}
Component {
AppInfo {
}
AppInfo {}
}
}
},
@@ -142,13 +129,11 @@ QtObject {
Component {
StackPage {
Component {
ServicesPage {
}
ServicesPage {}
}
Component {
NotificationsPage {
}
NotificationsPage {}
}
}
},
@@ -157,15 +142,13 @@ QtObject {
Component {
StackPage {
Component {
AboutPage {
}
AboutPage {}
}
}
}
]
readonly property Component placeholderComp: Component {
PlaceholderComp {
}
PlaceholderComp {}
}
component PlaceholderComp: Item {
@@ -55,6 +55,7 @@ PageBase {
enabled: Object.keys(model).length > 0
header: qsTr("Add new entry")
icon: "add"
last: true
label: qsTr("Add entry")
model: {
const present = new Set(Config.bar.tray.statusIcons.values.map(item => item.id));
@@ -0,0 +1,95 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import qs.Components
import qs.Modules.Settings.Common
PageBase {
id: root
readonly property var schemes: [
{
id: "oneDark",
label: qsTr("One Dark")
},
{
id: "nord",
label: qsTr("Nord")
},
{
id: "dracula",
label: qsTr("Dracula")
},
{
id: "githubDark",
label: qsTr("Github Dark")
},
{
id: "solarizedDark",
label: qsTr("Solarized Dark")
},
{
id: "monokai",
label: qsTr("Monokai")
},
{
id: "gruvboxDark",
label: qsTr("Gruvbox Dark")
},
{
id: "catppuccinMocha",
label: qsTr("Catppuccin Mocha")
},
{
id: "tokyoNight",
label: qsTr("Tokyo Night")
},
{
id: "ayuDark",
label: qsTr("Ayu Dark")
},
{
id: "palenight",
label: qsTr("Pale Night")
}
]
isSubPage: true
title: qsTr("Sidebar")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Tokens.spacing.extraSmall / 2
width: root.cappedWidth
SectionHeader {
first: true
text: qsTr("Appearance")
}
DialogSelectButton {
id: selectScheme
acceptLabel: qsTr("Confirm")
enabled: Object.keys(model).length > 0
header: qsTr("Select scheme")
first: true
last: true
icon: "add"
label: qsTr("Color scheme")
subtext: qsTr("Select the color scheme used for code blocks")
model: root.schemes
rootParent: root.flickable
onAccepted: {
if (!selectedItem)
return;
Config.llm.appearance.scheme = selectedItem;
}
}
}
}
@@ -89,6 +89,7 @@ PageBase {
header: qsTr("Add new entry")
icon: "add"
label: qsTr("Add entry")
last: true
model: {
const present = new Set(Config.utilities.quickToggles.values.map(item => item.id));
return Object.keys(root.builtinIcons).filter(id => !present.has(id)).map(id => ({
@@ -108,5 +109,18 @@ PageBase {
});
}
}
SectionHeader {
text: qsTr("AI chat")
}
NavRow {
text: qsTr("AI chat")
icon: "robot_2"
first: true
last: true
onClicked: root.sState.openSubPage(9)
}
}
}