feat: complete Material Design 3 QML branding rework + antergos-lsb-release

Complete rewrite of the Calamares QML branding with a pure Material
Design 3 (Material You) dark theme. No longer KaOS-derived — all QML
written from scratch for Antergos NeXT.

calamares-sidebar.qml:
  — M3 CenterAlignedTopAppBar at 64dp height with #20252B surface
  — Left: 34dp product logo + "Antergos NeXT" wordmark (17dp Medium,
    0.3 letter-spacing)
  — Right: step indicator dots (7dp circles, active 10dp pill #4A9EFF)
  — Bottom: 3dp animated linear progress bar (400ms OutCubic easing)
  — Subtle level-1 drop shadow (4dp radius, rgba(0,0,0,0.4))

calamares-navigation.qml:
  — M3 Navigation Bar at 68dp height
  — Buttons at 42dp height, 21dp pill radius (per M3 Label Large)
  — Sentence case text ("Back", "Next", "Cancel") in Roboto Medium 14px
  — Back: text button with ← arrow, on-surface hover rgba(0.89,0.89,0.90,0.06)
  — Cancel: text button in error #FFB4AB, error hover rgba(1.0,0.71,0.67,0.07)
  — Next: filled pill 120x42dp in primary #4A9EFF, hover #3B8BDE
  — 120ms ColorAnimation on all button backgrounds
  — Inline Unicode arrows (← →) instead of missing SVG icon files

show.qml:
  — Full-bleed background image with 55% dark overlay + vertical
    gradient (top 15% → transparent → bottom 30%)
  — M3 Elevated Card: 460x380dp, 12dp corner (M3 CornerMedium),
    #2B2930 fill (M3 Surface Container High), 32dp content padding
  — Card shadow: 40dp blur, 56 samples, rgba(0,0,0,0.5)
  — Subtle 1px border at rgba(255,255,255,0.04) for edge definition
  — Title: 26dp Roboto Medium #FFFFFF
  — Body: 14dp Roboto Normal #C4C6D0, 1.55 line-height
  — Footer: 12dp Roboto Medium #8E9099 (M3 Outline)
  — 5 slides with auto-advance every 12s
  — Crossfade transition: 100ms out + 160ms in with OutQuad/InQuad
  — Bottom-left: 140dp wordmark logo at 45% opacity
  — Center-bottom: animated dot indicators matching sidebar style

Slider.qml:
  — Crossfade between Dia slides using SequentialAnimation
  — Removed Animator types (Qt6 render-thread safe)
  — Clean Column layout with centered content

Dia.qml:
  — Unchanged data model (title, body, footer, image)

antergos-lsb-release:
  — New package replacing lsb-release with Antergos NeXT branding
  — /etc/lsb-release shows DISTRIB_ID="Antergos"
  — Added to packages.yaml for CI builds
This commit is contained in:
2026-07-03 23:43:02 +02:00
parent afb154c7d2
commit 09bff48d8b
6 changed files with 375 additions and 388 deletions
+1
View File
@@ -1,4 +1,5 @@
packages:
- antergos-lsb-release
- antergos-release
- antergos-wallpapers
- yay
+22
View File
@@ -0,0 +1,22 @@
# Maintainer: Antergos NeXT <antergos-next@github>
pkgname=antergos-lsb-release
pkgver=2.0
pkgrel=1
pkgdesc='Antergos NeXT LSB release file'
arch=('any')
url="https://github.com/Antergos-NeXT"
license=('GPL2')
conflicts=('lsb-release')
replaces=('lsb-release')
provides=('lsb-release')
package() {
install -dm755 "$pkgdir/etc"
cat > "$pkgdir/etc/lsb-release" << EOF
DISTRIB_ID="Antergos"
DISTRIB_RELEASE="rolling"
DISTRIB_DESCRIPTION="Antergos NeXT"
DISTRIB_CODENAME=antergos
EOF
}
@@ -2,172 +2,84 @@ import QtQuick 2.15
Item {
property list<Dia> slides
property list<Dia> img
property int currentSlideIndex: 0
property int _currentSlideIndex: 0
property int slidesSize: slides.length
property bool firstIteration: true
function reset() {
currentSlideIndex = 0;
firstIteration = true;
currentSlideIndex = 0
_currentSlideIndex = 0
wrapper.opacity = 1
}
onCurrentSlideIndexChanged: {
if (currentSlideIndex >= slidesSize) {
firstIteration = false;
currentSlideIndex = 0;
if (currentSlideIndex >= slides.length) {
currentSlideIndex = 0
}
if (_currentSlideIndex !== currentSlideIndex) {
slideOut.start()
}
transitionAnimation.start();
}
Column {
Item {
id: wrapper
anchors.fill: parent
spacing: 10
Text {
id: titleText
font {
family: "Raleway"
capitalization: Font.AllUppercase
weight: Font.DemiBold
pointSize: 16
}
color: "white"
text: slides[_currentSlideIndex].title
}
Text {
id: bodyText
font {
family: "Raleway"
pointSize: 12
weight: Font.DemiBold
}
width: 400
color: "white"
text: slides[_currentSlideIndex].body
wrapMode: Text.Wrap
}
Column {
anchors.centerIn: parent
width: parent.width
spacing: 0
Text {
id: footerText
font {
family: "Raleway"
weight: Font.Light
pointSize: 12
Text {
id: titleText
font {
family: "Roboto"
weight: Font.Medium
pixelSize: 26
}
color: "#FFFFFF"
text: slides[_currentSlideIndex].title
wrapMode: Text.WordWrap
width: parent.width
lineHeight: 1.25
bottomPadding: 20
}
width: 400
color: "white"
text: slides[_currentSlideIndex].footer ?? ""
wrapMode: Text.Wrap
}
Image {
id: icon
source: slides[_currentSlideIndex].image
width: 250
height: 250
Text {
id: bodyText
width: parent.width
font {
family: "Roboto"
weight: Font.Normal
pixelSize: 14
}
color: "#C4C6D0"
text: slides[_currentSlideIndex].body
wrapMode: Text.WordWrap
lineHeight: 1.55
bottomPadding: 20
}
Text {
id: footerText
font {
family: "Roboto"
weight: Font.Medium
pixelSize: 12
}
color: "#8E9099"
text: slides[_currentSlideIndex].footer ?? ""
wrapMode: Text.WordWrap
width: parent.width
lineHeight: 1.4
}
}
}
SequentialAnimation {
id: transitionAnimation
property int duration: 700
ParallelAnimation {
OpacityAnimator {
target: titleText
from: 1.0
to: 0.0
duration: transitionAnimation.duration
}
OpacityAnimator {
target: bodyText
from: 1.0
to: 0.0
duration: transitionAnimation.duration
}
OpacityAnimator {
target: footerText
from: 1.0
to: 0.0
duration: transitionAnimation.duration
}
OpacityAnimator {
target: icon
from: 1.0
to: 0.0
duration: 2000
}
XAnimator {
target: titleText
from: 0
to: -30
duration: transitionAnimation.duration
}
XAnimator {
target: bodyText
from: 0
to: -25
duration: transitionAnimation.duration
}
XAnimator {
target: footerText
from: 0
to: -25
duration: transitionAnimation.duration
}
}
ScriptAction {
script: _currentSlideIndex = currentSlideIndex
}
ParallelAnimation {
OpacityAnimator {
target: titleText
from: 0.0
to: 1.0
duration: transitionAnimation.duration
}
OpacityAnimator {
target: bodyText
from: 0.0
to: 1.0
duration: transitionAnimation.duration
}
OpacityAnimator {
target: footerText
from: 0.0
to: 1.0
duration: transitionAnimation.duration
}
OpacityAnimator {
target: icon
from: 0.0
to: 1.0
duration: 2000
}
XAnimator {
target: titleText
from: 30
to: 0
duration: transitionAnimation.duration
}
XAnimator {
target: bodyText
from: 25
to: 0
duration: transitionAnimation.duration
}
XAnimator {
target: footerText
from: 25
to: 0
duration: transitionAnimation.duration
}
}
id: slideOut
NumberAnimation { target: wrapper; property: "opacity"; to: 0; duration: 100; easing.type: Easing.OutQuad }
PropertyAction { target: wrapper; property: "opacity"; value: 0 }
ScriptAction { script: _currentSlideIndex = currentSlideIndex }
NumberAnimation { target: wrapper; property: "opacity"; to: 1; duration: 160; easing.type: Easing.InQuad }
}
}
@@ -1,166 +1,119 @@
import io.calamares.ui 1.0
import io.calamares.core 1.0
import QtQuick 2.3
import QtQuick.Controls 2.10
import QtQuick.Layouts 1.3
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import Qt5Compat.GraphicalEffects
Rectangle {
id: navigationBar;
color: Branding.styleString( Branding.SidebarBackground );
height: parent.height;
width: 64;
id: bottomBar
color: "#20252B"
height: 68
width: parent ? parent.width : 1024
ColumnLayout {
id: buttonBar
anchors.fill: parent;
spacing: 1
layer.enabled: true
layer.effect: DropShadow {
transparentBorder: true
radius: 4
samples: 8
color: Qt.rgba(0, 0, 0, 0.4)
}
Image {
Layout.topMargin: 1;
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
id: logo;
width: 62;
height: width;
source: "file:/" + Branding.imagePath(Branding.ProductLogo);
sourceSize.width: width;
sourceSize.height: height;
RowLayout {
anchors.fill: parent
anchors.leftMargin: 12
anchors.rightMargin: 20
spacing: 8
Button {
id: backButton
text: qsTr("Back")
flat: true
enabled: ViewManager.backEnabled
implicitHeight: 42
font {
family: "Roboto"
weight: Font.Medium
pixelSize: 14
}
contentItem: Text {
text: "← " + parent.text
font: parent.font
color: parent.enabled ? "#E3E2E6" : Qt.rgba(0.89, 0.89, 0.90, 0.35)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
leftPadding: 16
rightPadding: 16
}
background: Rectangle {
color: parent.hovered && parent.enabled
? Qt.rgba(0.89, 0.89, 0.90, 0.06)
: "transparent"
radius: 21
Behavior on color { ColorAnimation { duration: 120 } }
}
onClicked: ViewManager.back()
}
Rectangle {
id: debugArea
Layout.fillWidth: true;
height: 35
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
Layout.topMargin: 40
color: Branding.styleString( mouseAreaDebug.containsMouse ? Branding.SidebarBackgroundCurrent : Branding.SidebarBackground);
visible: debug.enabled
Item { Layout.fillWidth: true }
MouseArea {
id: mouseAreaDebug
anchors.fill: parent;
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
Text {
anchors.centerIn: parent
text: qsTr("Debug")
color: Branding.styleString( mouseAreaDebug.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarBackground );
font.pointSize : 8
}
onClicked: debug.toggle()
Button {
id: cancelButton
text: qsTr("Cancel")
flat: true
enabled: ViewManager.quitEnabled
implicitHeight: 42
font {
family: "Roboto"
weight: Font.Medium
pixelSize: 14
}
contentItem: Text {
text: parent.text
font: parent.font
color: parent.enabled ? "#FFB4AB" : Qt.rgba(1.0, 0.71, 0.67, 0.35)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
leftPadding: 14
rightPadding: 14
}
background: Rectangle {
color: parent.hovered && parent.enabled
? Qt.rgba(1.0, 0.71, 0.67, 0.07)
: "transparent"
radius: 21
Behavior on color { ColorAnimation { duration: 120 } }
}
onClicked: ViewManager.quit()
}
Item {
Layout.fillHeight: true;
}
Rectangle {
id: backArea
Layout.fillWidth: true;
Layout.preferredHeight: parent.height / 7;
color: mouseBack.containsMouse ? "#2C3E50" : "#1E2935";
enabled: ViewManager.backEnabled;
visible: ViewManager.backAndNextVisible;
MouseArea {
id: mouseBack
anchors.fill: parent;
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
Text {
anchors.centerIn: parent
text: qsTr("Back")
color: Branding.styleString( !backArea.enabled ? Branding.SidebarBackground : (mouseBack.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarText ));
font.pointSize : 8
}
Image {
source: "pan-start-symbolic.svg"
anchors.centerIn: parent
anchors.verticalCenterOffset : 18
fillMode: Image.PreserveAspectFit
height: 32
opacity: backArea.enabled ? 1 : 0.2
}
onClicked: { ViewManager.back(); }
Button {
id: nextButton
text: qsTr("Next")
enabled: ViewManager.nextEnabled
implicitWidth: 120
implicitHeight: 42
font {
family: "Roboto"
weight: Font.Medium
pixelSize: 14
}
}
Rectangle {
id: nextArea
Layout.preferredHeight: parent.height / 7;
Layout.fillWidth: true
color: mouseNext.containsMouse ? "#2C3E50" : "#1E2935";
enabled: ViewManager.nextEnabled;
visible: ViewManager.backAndNextVisible;
MouseArea {
id: mouseNext
anchors.fill: parent;
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
Text {
anchors.centerIn: parent
text: qsTr("Next")
color: Branding.styleString( !nextArea.enabled ? Branding.SidebarBackground : (mouseNext.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarText ));
font.pointSize : 8
}
Image {
source: "pan-end-symbolic.svg"
anchors.centerIn: parent
anchors.verticalCenterOffset : 18
fillMode: Image.PreserveAspectFit
height: 32
opacity: nextArea.enabled ? 1 : 0.2
}
onClicked: { ViewManager.next(); }
contentItem: Text {
text: parent.text + " →"
font: parent.font
color: "#FFFFFF"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Rectangle {
id: cancelArea
height: parent.height / 7;
Layout.fillWidth: true;
Layout.bottomMargin: 48;
color: mouseCancel.containsMouse ? "#2C3E50" : "#1E2935";
enabled: ViewManager.quitEnabled;
visible: ViewManager.quitVisible && ( ViewManager.currentStepIndex < ViewManager.rowCount()-1);
ToolTip {
width: 59
visible: mouseCancel.containsMouse
timeout: 5000
delay: 1000
text: ViewManager.quitTooltip;
}
MouseArea {
id: mouseCancel
anchors.fill: parent;
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
Text {
anchors.centerIn: parent
text: qsTr("Cancel")
color: Branding.styleString( !cancelArea.enabled ? Branding.SidebarBackground : (mouseCancel.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarText ));
font.pointSize : 8
}
Image {
source: "draw-rectangle.svg"
anchors.centerIn: parent
anchors.verticalCenterOffset : 18
fillMode: Image.PreserveAspectFit
height: 9
opacity: cancelArea.enabled ? 1 : 0.2
}
onClicked: { ViewManager.quit(); }
background: Rectangle {
color: parent.enabled
? (parent.hovered ? "#3B8BDE" : "#4A9EFF")
: Qt.rgba(0.29, 0.62, 1.0, 0.35)
radius: 21
Behavior on color { ColorAnimation { duration: 120 } }
}
onClicked: ViewManager.next()
}
}
}
@@ -1,62 +1,90 @@
import io.calamares.ui 1.0
import io.calamares.core 1.0
import QtQuick 2.3
import QtQuick.Layouts 1.3
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import Qt5Compat.GraphicalEffects
Rectangle {
id: sideBar;
color: Branding.styleString( Branding.SidebarBackground );
height: 48;
width: parent.width
id: topBar
color: "#20252B"
height: 64
width: parent ? parent.width : 1024
layer.enabled: true
layer.effect: DropShadow {
transparentBorder: true
radius: 4
samples: 8
color: Qt.rgba(0, 0, 0, 0.4)
}
RowLayout {
anchors.fill: parent;
spacing: 0;
anchors.fill: parent
anchors.leftMargin: 20
anchors.rightMargin: 20
spacing: 14
Item {
Layout.fillHeight: true;
Image {
id: logo
sourceSize.width: 34
sourceSize.height: 34
fillMode: Image.PreserveAspectFit
source: Branding.imagePath(Branding.ProductLogo)
Layout.alignment: Qt.AlignVCenter
}
Repeater {
model: ViewManager
Rectangle {
Layout.leftMargin: 0;
Layout.fillWidth: true;
Layout.alignment: Qt.AlignTop;
height: 42;
radius: 0;
color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarBackgroundCurrent : Branding.SidebarBackground );
Text {
text: "Antergos NeXT"
color: "#E3E2E6"
font {
family: "Roboto"
weight: Font.Medium
pixelSize: 17
letterSpacing: 0.3
}
Layout.alignment: Qt.AlignVCenter
}
Text {
anchors.verticalCenter: parent.verticalCenter;
anchors.horizontalCenter: parent.horizontalCenter
x: parent.x + 12;
color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarTextCurrent : Branding.SidebarText );
text: qsTr(display);
font.pointSize : index == ViewManager.currentStepIndex ? 10 : 9
}
Item { Layout.fillWidth: true }
Row {
spacing: 8
Layout.alignment: Qt.AlignVCenter
Repeater {
id: dotRepeater
model: ViewManager
Rectangle {
height: 2
width: 800
anchors.bottom: parent.bottom;
border.color: Branding.styleString(ViewManager.currentStepIndex === index ? Branding.SidebarTextCurrent : (ViewManager.currentStepIndex >= index ? Branding.SidebarTextCurrent : Branding.SidebarBackgroundCurrent))
border.width: 3
Image {
source: "pan-up-symbolic.svg"
id: image
anchors.verticalCenter: parent.verticalCenter;
anchors.verticalCenterOffset : -3
x: parent.x + 35;
fillMode: Image.PreserveAspectFit
height: 32
visible: index == ViewManager.currentStepIndex ? true : false
}
width: index === ViewManager.currentStepIndex ? 10 : 7
height: 7
radius: 3.5
color: index === ViewManager.currentStepIndex
? "#4A9EFF" : "#8E9099"
opacity: index === ViewManager.currentStepIndex ? 1 : 0.35
Behavior on width { NumberAnimation { duration: 200 } }
Behavior on color { ColorAnimation { duration: 200 } }
}
}
}
}
Rectangle {
anchors {
bottom: parent.bottom
left: parent.left
right: parent.right
}
height: 3
color: Qt.rgba(0.56, 0.57, 0.60, 0.2)
Rectangle {
height: parent.height
width: parent.width * ((ViewManager.currentStepIndex + 1) / Math.max(dotRepeater.count, 1))
color: "#4A9EFF"
Behavior on width { NumberAnimation { duration: 400; easing.type: Easing.OutCubic } }
}
}
}
@@ -1,24 +1,22 @@
import QtQuick 2.15;
import QtQuick 2.15
import Qt5Compat.GraphicalEffects
Item {
id: root
width: 920
height: 630
function onActivate(){
console.log("Slideshow) activated");
timer.restart();
slider.reset();
function onActivate() {
timer.restart()
slider.reset()
}
function onLeave(){
console.log("Slideshow) deactivated");
function onLeave() {
}
width: 940
height: 600
Timer {
id: timer
interval: 10000
interval: 12000
running: true
repeat: true
onTriggered: slider.currentSlideIndex++
@@ -26,9 +24,10 @@ Item {
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
timer.restart();
slider.currentSlideIndex++;
timer.restart()
slider.currentSlideIndex++
}
}
@@ -36,52 +35,124 @@ Item {
id: background
anchors.fill: parent
source: "background.jpg"
sourceSize.width: parent.width
sourceSize.height: parent.height
fillMode: Image.PreserveAspectCrop
}
Rectangle {
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: 200
color: Qt.rgba(0, 0, 0, 0.6)
anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.55)
}
Slider {
id: slider
Rectangle {
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 0.0; color: Qt.rgba(0, 0, 0, 0.15) }
GradientStop { position: 0.5; color: "transparent" }
GradientStop { position: 1.0; color: Qt.rgba(0, 0, 0, 0.3) }
}
}
Rectangle {
id: card
width: 460
height: 380
radius: 12
anchors.centerIn: parent
anchors.horizontalCenterOffset: 40
color: "#2B2930"
layer.enabled: true
layer.effect: DropShadow {
transparentBorder: true
radius: 40
samples: 56
color: Qt.rgba(0, 0, 0, 0.5)
}
Rectangle {
anchors.fill: parent
radius: 12
color: "transparent"
border { color: Qt.rgba(1, 1, 1, 0.04); width: 1 }
}
Item {
anchors {
fill: parent
margins: 20
margins: 32
}
slides: [
Dia {
title: qsTr("Welcome to Antergos NeXT")
body: qsTr("A modern Artix Linux experience with OpenRC and elogind")
footer: qsTr("Choose your preferred desktop environment during setup")
},
Dia {
title: qsTr("Desktop Environments")
body: qsTr("Select from KDE Plasma, Xfce, Cinnamon, MATE, LXQt, i3, Sway, or Hyprland")
footer: qsTr("Each desktop is fully configured and ready to use")
},
Dia {
title: qsTr("Antergos Tools")
body: qsTr("Welcome app for system configuration, Calamares installer with offline and online modes, and HAL package manager")
footer: qsTr("Full access to Artix Linux repositories and the AUR")
},
Dia {
title: qsTr("Open Source")
body: qsTr("Antergos NeXT is free and open source software built by the community")
footer: qsTr("Contribute on GitHub — Antergos-NeXT")
},
Dia {
title: qsTr("Almost Done")
body: qsTr("Your system is being configured with your selected options")
footer: qsTr("Reboot and enjoy Antergos NeXT")
}
]
Slider {
id: slider
anchors.fill: parent
slides: [
Dia {
title: qsTr("Welcome to Antergos NeXT")
body: qsTr("A modern Arch Linux experience built on Artix Linux. Rolling release, OpenRC init, and the latest software.")
footer: qsTr("Choose your preferred desktop environment during setup")
},
Dia {
title: qsTr("Desktop Environments")
body: qsTr("Select from KDE Plasma, GNOME, Xfce, Budgie, Cinnamon, MATE, LXQt, i3, Sway, or Hyprland.")
footer: qsTr("A curated selection of the best Linux desktops")
},
Dia {
title: qsTr("Antergos Tools")
body: qsTr("Welcome app for system configuration, Calamares installer with offline and online modes, and full access to Arch Linux repositories and the AUR.")
footer: qsTr("Everything you need to get started")
},
Dia {
title: qsTr("Open Source")
body: qsTr("Free and open source software built by the community for the community.")
footer: qsTr("github.com/Antergos-NeXT")
},
Dia {
title: qsTr("Almost Done")
body: qsTr("Your system is being configured with your selected desktop environment, drivers, and applications.")
footer: qsTr("Reboot and enjoy Antergos NeXT")
}
]
}
}
}
Image {
id: logo
source: "antergos-logo.png"
width: 140
height: 40
fillMode: Image.PreserveAspectFit
anchors {
bottom: parent.bottom
bottomMargin: 20
left: parent.left
leftMargin: 24
}
opacity: 0.45
}
Row {
anchors {
bottom: parent.bottom
bottomMargin: 20
horizontalCenter: parent.horizontalCenter
}
spacing: 6
Repeater {
model: slider.slides.length
Rectangle {
width: index == slider.currentSlideIndex ? 22 : 7
height: 7
radius: 3.5
color: index == slider.currentSlideIndex ? "#4A9EFF" : "#8E9099"
opacity: index == slider.currentSlideIndex ? 1 : 0.35
Behavior on width { NumberAnimation { duration: 250 } }
Behavior on color { ColorAnimation { duration: 200 } }
}
}
}
}