3d1168ff8c
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
398 lines
13 KiB
QML
Executable File
398 lines
13 KiB
QML
Executable File
import QtQuick 2.0
|
|
import SddmComponents 2.0
|
|
|
|
Rectangle {
|
|
id: root
|
|
width: 1920
|
|
height: 1200
|
|
|
|
readonly property color accentColor: "#8cc63f" // brand_green
|
|
readonly property color bgDark: "#1e1526" // base_bg
|
|
readonly property color textPrimary: "#f2f2f2" // text_primary
|
|
readonly property color textMuted: "#a8a8a8" // text_secondary
|
|
readonly property color fieldBg: "#1f2225" // surface_bg
|
|
readonly property color fieldBorder: "#4d3461" // menu_border (purple tint)
|
|
readonly property color errorColor: "#da4453" // error_color
|
|
|
|
property int sessionIndex: sessionModel.lastIndex
|
|
|
|
Connections {
|
|
target: sddm
|
|
onLoginFailed: {
|
|
errorMsg.text = "Login failed — check your credentials."
|
|
passwordInput.text = ""
|
|
passwordInput.focus = true
|
|
shakeAnim.start()
|
|
}
|
|
onLoginSucceeded: {
|
|
errorMsg.text = ""
|
|
}
|
|
}
|
|
|
|
Image {
|
|
anchors.fill: parent
|
|
source: "assets/background.svg"
|
|
fillMode: Image.PreserveAspectCrop
|
|
smooth: true
|
|
asynchronous: false
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: "#000000"
|
|
opacity: 0.25
|
|
}
|
|
|
|
Item {
|
|
id: logoArea
|
|
width: 120
|
|
height: 120
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.top: parent.top
|
|
anchors.topMargin: parent.height * 0.10
|
|
|
|
Rectangle {
|
|
anchors.centerIn: parent
|
|
width: parent.width * 1.6
|
|
height: parent.height * 1.6
|
|
radius: width / 2
|
|
color: accentColor
|
|
opacity: 0.06
|
|
}
|
|
|
|
Image {
|
|
id: logo
|
|
anchors.fill: parent
|
|
source: "assets/logo.png"
|
|
sourceSize: Qt.size(200, 200)
|
|
smooth: true
|
|
}
|
|
}
|
|
|
|
Text {
|
|
id: brandLabel
|
|
text: "NexusOS"
|
|
color: textPrimary
|
|
font.family: "Sans"
|
|
font.pixelSize: 28
|
|
font.letterSpacing: 6
|
|
font.weight: Font.Light
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.top: logoArea.bottom
|
|
anchors.topMargin: 16
|
|
}
|
|
|
|
Rectangle {
|
|
id: loginBox
|
|
width: 360
|
|
height: loginColumn.height + 60
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.top: brandLabel.bottom
|
|
anchors.topMargin: parent.height * 0.08
|
|
color: Qt.rgba(15/255, 22/255, 38/255, 0.75)
|
|
radius: 12
|
|
border.color: fieldBorder
|
|
border.width: 1
|
|
|
|
SequentialAnimation {
|
|
id: shakeAnim
|
|
NumberAnimation { target: loginBox; property: "x"; to: loginBox.x - 10; duration: 50 }
|
|
NumberAnimation { target: loginBox; property: "x"; to: loginBox.x + 10; duration: 50 }
|
|
NumberAnimation { target: loginBox; property: "x"; to: loginBox.x - 6; duration: 50 }
|
|
NumberAnimation { target: loginBox; property: "x"; to: loginBox.x + 6; duration: 50 }
|
|
NumberAnimation { target: loginBox; property: "x"; to: loginBox.x; duration: 40 }
|
|
}
|
|
|
|
Column {
|
|
id: loginColumn
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: parent.top
|
|
anchors.margins: 30
|
|
spacing: 14
|
|
|
|
Rectangle {
|
|
id: sessionBox
|
|
width: parent.width
|
|
height: 40
|
|
color: fieldBg
|
|
radius: 6
|
|
border.color: sessionDropdown.visible ? accentColor : fieldBorder
|
|
border.width: 1
|
|
|
|
Text {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 14
|
|
anchors.right: sessionArrow.left
|
|
anchors.rightMargin: 8
|
|
text: sessionModel.data(sessionModel.index(sessionIndex, 0), Qt.DisplayRole) || "Session"
|
|
color: textPrimary
|
|
font.pixelSize: 13
|
|
elide: Text.ElideRight
|
|
}
|
|
|
|
Text {
|
|
id: sessionArrow
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 14
|
|
text: sessionDropdown.visible ? "▲" : "▼"
|
|
color: textMuted
|
|
font.pixelSize: 10
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
if (!sessionDropdown.visible) {
|
|
var pos = sessionBox.mapToItem(root, 0, sessionBox.height)
|
|
sessionDropdown.x = pos.x
|
|
sessionDropdown.y = pos.y + 2
|
|
sessionDropdown.width = sessionBox.width
|
|
}
|
|
sessionDropdown.visible = !sessionDropdown.visible
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 44
|
|
color: fieldBg
|
|
radius: 6
|
|
border.color: usernameInput.activeFocus ? accentColor : fieldBorder
|
|
border.width: 1
|
|
|
|
TextInput {
|
|
id: usernameInput
|
|
anchors.fill: parent
|
|
anchors.leftMargin: 14
|
|
anchors.rightMargin: 14
|
|
verticalAlignment: TextInput.AlignVCenter
|
|
color: textPrimary
|
|
font.pixelSize: 14
|
|
clip: true
|
|
text: userModel.lastUser
|
|
|
|
Keys.onTabPressed: passwordInput.forceActiveFocus()
|
|
Keys.onReturnPressed: sddm.login(usernameInput.text, passwordInput.text, sessionIndex)
|
|
}
|
|
|
|
Text {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 14
|
|
text: "Username"
|
|
color: textMuted
|
|
font.pixelSize: 14
|
|
visible: usernameInput.text.length === 0 && !usernameInput.activeFocus
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 44
|
|
color: fieldBg
|
|
radius: 6
|
|
border.color: passwordInput.activeFocus ? accentColor : fieldBorder
|
|
border.width: 1
|
|
|
|
TextInput {
|
|
id: passwordInput
|
|
anchors.fill: parent
|
|
anchors.leftMargin: 14
|
|
anchors.rightMargin: 14
|
|
verticalAlignment: TextInput.AlignVCenter
|
|
color: textPrimary
|
|
font.pixelSize: 14
|
|
echoMode: TextInput.Password
|
|
clip: true
|
|
focus: true
|
|
|
|
Keys.onReturnPressed: sddm.login(usernameInput.text, passwordInput.text, sessionIndex)
|
|
}
|
|
|
|
Text {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 14
|
|
text: "Password"
|
|
color: textMuted
|
|
font.pixelSize: 14
|
|
visible: passwordInput.text.length === 0 && !passwordInput.activeFocus
|
|
}
|
|
}
|
|
|
|
Text {
|
|
id: errorMsg
|
|
width: parent.width
|
|
text: ""
|
|
color: errorColor
|
|
font.pixelSize: 12
|
|
horizontalAlignment: Text.AlignHCenter
|
|
wrapMode: Text.WordWrap
|
|
visible: text !== ""
|
|
}
|
|
|
|
Rectangle {
|
|
id: loginButton
|
|
width: parent.width
|
|
height: 44
|
|
radius: 6
|
|
color: loginMouse.pressed
|
|
? Qt.darker(accentColor, 1.3)
|
|
: loginMouse.containsMouse
|
|
? Qt.lighter(accentColor, 1.15)
|
|
: accentColor
|
|
|
|
Behavior on color { ColorAnimation { duration: 150 } }
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
text: "LOGIN"
|
|
color: "#0a0a00" // text_on_accent (dark on lime green)
|
|
font.pixelSize: 14
|
|
font.letterSpacing: 3
|
|
font.weight: Font.DemiBold
|
|
}
|
|
|
|
MouseArea {
|
|
id: loginMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: sddm.login(usernameInput.text, passwordInput.text, sessionIndex)
|
|
}
|
|
}
|
|
|
|
Item {
|
|
width: parent.width
|
|
height: 30
|
|
|
|
Row {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
spacing: 30
|
|
|
|
Text {
|
|
text: "⏻ Shutdown"
|
|
color: textMuted
|
|
font.pixelSize: 12
|
|
opacity: shutdownMouse.containsMouse ? 1.0 : 0.7
|
|
Behavior on opacity { NumberAnimation { duration: 120 } }
|
|
|
|
MouseArea {
|
|
id: shutdownMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: sddm.powerOff()
|
|
}
|
|
}
|
|
|
|
Text {
|
|
text: "↻ Reboot"
|
|
color: textMuted
|
|
font.pixelSize: 12
|
|
opacity: rebootMouse.containsMouse ? 1.0 : 0.7
|
|
Behavior on opacity { NumberAnimation { duration: 120 } }
|
|
|
|
MouseArea {
|
|
id: rebootMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: sddm.reboot()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: sessionDropdown
|
|
visible: false
|
|
z: 999
|
|
color: fieldBg
|
|
radius: 6
|
|
border.color: fieldBorder
|
|
border.width: 1
|
|
height: sessionList.contentHeight
|
|
clip: true
|
|
|
|
ListView {
|
|
id: sessionList
|
|
anchors.fill: parent
|
|
model: sessionModel
|
|
interactive: false
|
|
|
|
delegate: Rectangle {
|
|
width: sessionList.width
|
|
height: 36
|
|
color: sessionItemMouse.containsMouse ? Qt.lighter(fieldBg, 1.4) : "transparent"
|
|
radius: 4
|
|
|
|
Text {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 14
|
|
text: model.name || ""
|
|
color: index === sessionIndex ? accentColor : textPrimary
|
|
font.pixelSize: 13
|
|
}
|
|
|
|
MouseArea {
|
|
id: sessionItemMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
sessionIndex = index
|
|
sessionDropdown.visible = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Column {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: parent.height * 0.05
|
|
spacing: 2
|
|
|
|
Text {
|
|
id: clockText
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
color: textPrimary
|
|
font.family: "Sans"
|
|
font.pixelSize: 42
|
|
font.weight: Font.Thin
|
|
}
|
|
|
|
Text {
|
|
id: dateText
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
color: textMuted
|
|
font.family: "Sans"
|
|
font.pixelSize: 14
|
|
font.letterSpacing: 2
|
|
}
|
|
|
|
Timer {
|
|
interval: 1000
|
|
running: true
|
|
repeat: true
|
|
triggeredOnStart: true
|
|
onTriggered: {
|
|
var d = new Date()
|
|
clockText.text = Qt.formatTime(d, "hh:mm")
|
|
dateText.text = Qt.formatDate(d, "dddd, MMMM d")
|
|
}
|
|
}
|
|
}
|
|
}
|