feat: add custom SDDM login theme

This commit is contained in:
hhhh hgfh 2026-10-05 00:37:52 +03:00
parent 3f0609bcfc
commit 7ae4243548
4 changed files with 241 additions and 0 deletions

View file

@ -5,6 +5,7 @@
./hardware-configuration.nix
../../modules/desktop.nix
../../modules/hardware.nix
../../modules/login-theme.nix
../../modules/packages
../../modules/system.nix
../../modules/users.nix

View file

@ -0,0 +1,26 @@
{ pkgs, ... }:
let
theme = pkgs.stdenvNoCC.mkDerivation {
pname = "sddm-custom-environment";
version = "1.0";
src = ../../sddm;
dontBuild = true;
installPhase = ''
runHook preInstall
themeDir="$out/share/sddm/themes/custom-environment"
mkdir -p "$themeDir"
cp Main.qml metadata.desktop "$themeDir/"
cp ${../../wallpapers/night_city.jpg} "$themeDir/background.jpg"
cp ${../../wallpapers/kotost.png} "$themeDir/avatar.png"
cp ${pkgs.nerd-fonts.profont}/share/fonts/truetype/NerdFonts/ProFont/ProFontWindowsNerdFontMono-Regular.ttf "$themeDir/font.ttf"
runHook postInstall
'';
};
in
{
system.build.sddmTheme = theme;
environment.systemPackages = [ theme ];
services.displayManager.sddm.theme = "custom-environment";
services.displayManager.sddm.extraPackages = [ pkgs.qt6.qtimageformats ];
}

205
sddm/Main.qml Normal file
View file

@ -0,0 +1,205 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Effects
Rectangle {
id: root
width: 1920
height: 1080
color: "#223638"
property date now: new Date()
property bool busy: false
property string message: ""
readonly property color cream: "#eee8dd"
readonly property color muted: "#bcb5ab"
readonly property color red: "#bc3b3b"
readonly property color dark: "#1c1717"
FontLoader { id: face; source: "font.ttf" }
Timer { interval: 1000; running: true; repeat: true; onTriggered: root.now = new Date() }
function login() {
if (busy) return
if (!username.text.trim() || session.count === 0) {
message = "Enter a username and select a session."
return
}
message = ""
busy = true
sddm.login(username.text.trim(), password.text, session.currentIndex)
}
Connections {
target: sddm
function onLoginFailed() {
root.busy = false
root.message = "Login failed. Please try again."
password.clear()
password.forceActiveFocus()
}
function onLoginSucceeded() { root.message = "Welcome back!" }
function onInformationMessage(message) { root.message = message }
}
Image {
id: wallpaper
anchors.fill: parent
source: "background.jpg"
fillMode: Image.PreserveAspectCrop
visible: false
}
MultiEffect {
anchors.fill: parent
source: wallpaper
blurEnabled: true
blurMax: 64
blur: 1.0
brightness: -0.2
}
Rectangle { anchors.fill: parent; color: "#30223638" }
component Card: Rectangle {
radius: 25
color: "#991c2827"
}
component LabelText: Text {
color: root.cream
font.family: face.name
font.pixelSize: 20
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
component Action: Button {
id: action
property color fill: "#cda67d"
font.family: face.name
font.pixelSize: 18
background: Rectangle {
radius: 20
color: action.down ? Qt.darker(action.fill, 1.2) : action.fill
border.width: action.activeFocus ? 2 : 0
border.color: root.cream
opacity: action.enabled ? 1 : 0.5
}
contentItem: Text {
text: action.text
font: action.font
color: root.dark
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Item {
width: 760
height: 650
anchors.centerIn: parent
scale: Math.min(1, root.width / 900, root.height / 780)
Card {
width: 360; height: 380
LabelText { x: 20; y: 32; width: 320; text: "NixOS · " + sddm.hostName; color: root.muted }
LabelText { x: 20; y: 76; width: 320; text: "Log in"; font.pixelSize: 56 }
Rectangle {
x: 20; y: 185; width: 320; height: 70; radius: 20; color: root.red
LabelText { x: 18; y: 6; text: "Username"; color: root.dark; font.pixelSize: 14 }
TextField {
id: username
x: 10; y: 25; width: 300; height: 40
text: userModel.lastUser
color: root.dark
font.family: face.name; font.pixelSize: 28
selectByMouse: true
enabled: !root.busy
background: Item {}
onAccepted: password.forceActiveFocus()
KeyNavigation.tab: password
}
}
Rectangle {
x: 20; y: 275; width: 320; height: 70; radius: 20; color: root.red
LabelText { x: 18; y: 6; text: "Password"; color: root.dark; font.pixelSize: 14 }
TextField {
id: password
x: 10; y: 25; width: 300; height: 40
color: root.dark
font.family: face.name; font.pixelSize: 28
echoMode: TextInput.Password
selectByMouse: true
enabled: !root.busy
background: Item {}
onAccepted: root.login()
KeyNavigation.tab: session
KeyNavigation.backtab: username
}
}
}
Card {
y: 410; width: 360; height: 160
LabelText { y: 4; width: 360; height: 116; text: Qt.formatDateTime(root.now, "HH:mm"); font.pixelSize: 96 }
LabelText { y: 122; width: 360; text: "Welcome back"; color: root.muted; font.pixelSize: 18 }
}
Card {
x: 400; width: 360; height: 650
Rectangle {
x: 116; y: 26; width: 128; height: 128
radius: 24; color: root.cream; border.width: 4; border.color: root.red
Image { anchors.fill: parent; anchors.margins: 6; source: "avatar.png"; fillMode: Image.PreserveAspectFit }
}
LabelText { y: 168; width: 360; text: Qt.formatDateTime(root.now, "ddd").toUpperCase(); font.pixelSize: 56; font.bold: true }
LabelText { y: 236; width: 360; text: Qt.formatDateTime(root.now, "dd MMMM, yyyy"); color: root.muted }
}
Card {
x: 400; y: 330; width: 360; height: 320; color: "#f01c1717"
LabelText { y: 16; width: 360; text: "Desktop session"; color: root.muted; font.pixelSize: 16 }
ComboBox {
id: session
x: 20; y: 48; width: 320; height: 42
model: sessionModel
textRole: "name"
currentIndex: Math.max(0, sessionModel.lastIndex)
enabled: !root.busy
font.family: face.name; font.pixelSize: 18
palette.button: "#332a29"
palette.buttonText: root.cream
palette.text: root.cream
palette.base: root.dark
palette.highlight: root.red
KeyNavigation.tab: loginButton
KeyNavigation.backtab: password
}
Row {
x: 20; y: 112; spacing: 20
Action { width: 150; height: 75; text: "Restart"; enabled: sddm.canReboot && !root.busy; onClicked: sddm.reboot() }
Action { width: 150; height: 75; text: "Power off"; enabled: sddm.canPowerOff && !root.busy; onClicked: sddm.powerOff() }
}
Action {
id: loginButton
x: 20; y: 205; width: 320; height: 70
fill: root.red
text: root.busy ? "Logging in…" : "Log in"
font.pixelSize: 30
enabled: !root.busy && session.count > 0
onClicked: root.login()
KeyNavigation.tab: username
KeyNavigation.backtab: session
}
LabelText {
x: 12; y: 282; width: 336; height: 32
text: root.message
font.pixelSize: 12
color: root.cream
wrapMode: Text.WordWrap
}
}
}
Component.onCompleted: {
if (username.text) password.forceActiveFocus()
else username.forceActiveFocus()
}
}

9
sddm/metadata.desktop Normal file
View file

@ -0,0 +1,9 @@
[SddmGreeterTheme]
Name=Custom environment
Description=Two-column login screen with ProFont and translucent cards
Type=sddm-theme
Version=1.0
MainScript=Main.qml
Theme-Id=custom-environment
Theme-API=2.0
QtVersion=6