Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Binary file added .github/assets/bongocat.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/dino.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/kurukuru.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
79 changes: 79 additions & 0 deletions .github/assets/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions .github/assets/pam.d/fprint
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#%PAM-1.0

auth required pam_fprintd.so max-tries=1
6 changes: 6 additions & 0 deletions .github/assets/pam.d/passwd
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#%PAM-1.0

auth required pam_faillock.so preauth
auth [success=1 default=bad] pam_unix.so nullok
auth [default=die] pam_faillock.so authfail
auth required pam_faillock.so authsucc
19 changes: 19 additions & 0 deletions .github/assets/shaders/opacitymask.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#version 440

layout(location = 0) in vec2 qt_TexCoord0;
layout(location = 0) out vec4 fragColor;

layout(std140, binding = 0) uniform buf {
// qt_Matrix and qt_Opacity must always be both present
// if the built-in vertex shader is used.
mat4 qt_Matrix;
float qt_Opacity;
};

layout(binding = 1) uniform sampler2D source;
layout(binding = 2) uniform sampler2D maskSource;

void main()
{
fragColor = texture(source, qt_TexCoord0.st) * (texture(maskSource, qt_TexCoord0.st).a) * qt_Opacity;
}
Binary file added .github/assets/shaders/opacitymask.frag.qsb
Binary file not shown.
5 changes: 5 additions & 0 deletions .github/assets/wrap_term_launch.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env sh

cat ~/.local/state/caelestia/sequences.txt 2>/dev/null

exec "$@"
8 changes: 8 additions & 0 deletions .github/components/Anim.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import qs.config
import QtQuick

NumberAnimation {
duration: Appearance.anim.durations.normal
easing.type: Easing.BezierSpline
easing.bezierCurve: Appearance.anim.curves.standard
}
8 changes: 8 additions & 0 deletions .github/components/CAnim.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import qs.config
import QtQuick

ColorAnimation {
duration: Appearance.anim.durations.normal
easing.type: Easing.BezierSpline
easing.bezierCurve: Appearance.anim.curves.standard
}
230 changes: 230 additions & 0 deletions .github/components/CategoryNavbar.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
pragma ComponentBehavior: Bound

import qs.components
import qs.components.controls
import qs.components.containers
import qs.services
import qs.config
import Quickshell
import QtQuick
import QtQuick.Layouts

StyledRect {
id: root

required property var categories
required property string activeCategory
property bool showScrollButtons: true
property bool showExtraContent: false
property Component extraContent: null

signal categoryChanged(string categoryId)

color: Colours.layer(Colours.palette.m3surfaceContainer, 2)
radius: Appearance.rounding.normal

visible: opacity > 0
implicitHeight: tabsRow.height + Appearance.padding.small + Appearance.padding.normal
clip: true

function scrollToActiveTab(): void {
Qt.callLater(() => {
if (!tabsFlickable || !tabsRow)
return;

const currentIndex = root.categories.findIndex(cat => cat.id === root.activeCategory);
if (currentIndex === -1)
return;

let tabX = 0;
for (let i = 0; i < currentIndex && i < tabsRow.children.length; i++) {
const child = tabsRow.children[i];
if (child) {
tabX += child.width + tabsRow.spacing;
}
}

const activeTab = tabsRow.children[currentIndex];
if (!activeTab)
return;

const tabWidth = activeTab.width;
const viewportStart = tabsFlickable.contentX;
const viewportEnd = tabsFlickable.contentX + tabsFlickable.width;

if (tabX < viewportStart) {
tabsFlickable.contentX = tabX;
} else if (tabX + tabWidth > viewportEnd) {
tabsFlickable.contentX = Math.min(tabsFlickable.contentWidth - tabsFlickable.width, tabX + tabWidth - tabsFlickable.width);
}
});
}

RowLayout {
id: tabsContent
anchors.fill: parent
anchors.leftMargin: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.normal
anchors.topMargin: Appearance.padding.small
anchors.bottomMargin: Appearance.padding.smaller
spacing: Appearance.spacing.smaller

IconButton {
icon: "chevron_left"
visible: root.showScrollButtons && tabsFlickable.contentWidth > tabsFlickable.width
type: IconButton.Text
radius: Appearance.rounding.small
padding: Appearance.padding.small
onClicked: {
tabsFlickable.contentX = Math.max(0, tabsFlickable.contentX - 100);
}
}

StyledFlickable {
id: tabsFlickable
Layout.fillWidth: true
Layout.preferredHeight: tabsRow.height
flickableDirection: Flickable.HorizontalFlick
contentWidth: tabsRow.width
clip: true

Behavior on contentX {
Anim {
duration: Appearance.anim.durations.normal
easing.bezierCurve: Appearance.anim.curves.emphasized
}
}

MouseArea {
anchors.fill: parent
propagateComposedEvents: true

onWheel: wheel => {
const delta = wheel.angleDelta.y || wheel.angleDelta.x;
tabsFlickable.contentX = Math.max(0, Math.min(tabsFlickable.contentWidth - tabsFlickable.width, tabsFlickable.contentX - delta));
wheel.accepted = true;
}

onPressed: mouse => {
mouse.accepted = false;
}
}

Item {
implicitWidth: tabsRow.width
implicitHeight: tabsRow.height

StyledRect {
id: activeIndicator

property Item activeTab: {
for (let i = 0; i < tabsRepeater.count; i++) {
const tab = tabsRepeater.itemAt(i);
if (tab && tab.isActive) {
return tab;
}
}
return null;
}

visible: activeTab !== null
color: Colours.palette.m3primary
radius: 10

x: activeTab ? activeTab.x : 0
y: activeTab ? activeTab.y : 0
width: activeTab ? activeTab.width : 0
height: activeTab ? activeTab.height : 0

Behavior on x {
Anim {
duration: Appearance.anim.durations.normal
easing.bezierCurve: Appearance.anim.curves.emphasized
}
}

Behavior on width {
Anim {
duration: Appearance.anim.durations.normal
easing.bezierCurve: Appearance.anim.curves.emphasized
}
}
}

Row {
id: tabsRow
spacing: Appearance.spacing.small

Repeater {
id: tabsRepeater
model: root.categories

delegate: Item {
required property var modelData
required property int index

property bool isActive: root.activeCategory === modelData.id

implicitWidth: tabContent.width + Appearance.padding.normal * 2
implicitHeight: tabContent.height + Appearance.padding.smaller * 2

StateLayer {
anchors.fill: parent
radius: 6
function onClicked(): void {
root.categoryChanged(modelData.id);

const tabLeft = parent.x;
const tabRight = parent.x + parent.width;
const viewLeft = tabsFlickable.contentX;
const viewRight = tabsFlickable.contentX + tabsFlickable.width;

const targetX = tabLeft - (tabsFlickable.width - parent.width) / 2;

tabsFlickable.contentX = Math.max(0, Math.min(tabsFlickable.contentWidth - tabsFlickable.width, targetX));
}
}

Row {
id: tabContent
anchors.centerIn: parent
spacing: Appearance.spacing.smaller

MaterialIcon {
anchors.verticalCenter: parent.verticalCenter
text: modelData.icon
font.pointSize: Appearance.font.size.small
color: isActive ? Colours.palette.m3surface : Colours.palette.m3onSurfaceVariant
}

StyledText {
anchors.verticalCenter: parent.verticalCenter
text: modelData.name
font.pointSize: Appearance.font.size.small
color: isActive ? Colours.palette.m3surface : Colours.palette.m3onSurfaceVariant
}
}
}
}
}
}
}

IconButton {
icon: "chevron_right"
visible: root.showScrollButtons && tabsFlickable.contentWidth > tabsFlickable.width
type: IconButton.Text
radius: Appearance.rounding.small
padding: Appearance.padding.small
onClicked: {
tabsFlickable.contentX = Math.min(tabsFlickable.contentWidth - tabsFlickable.width, tabsFlickable.contentX + 100);
}
}

Loader {
Layout.fillHeight: true
active: root.showExtraContent && root.extraContent !== null
sourceComponent: root.extraContent
}
}
}
31 changes: 31 additions & 0 deletions .github/components/ConnectionHeader.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import qs.components
import qs.services
import qs.config
import QtQuick
import QtQuick.Layouts

ColumnLayout {
id: root

required property string icon
required property string title

spacing: Appearance.spacing.normal
Layout.alignment: Qt.AlignHCenter

MaterialIcon {
Layout.alignment: Qt.AlignHCenter
animate: true
text: root.icon
font.pointSize: Appearance.font.size.extraLarge * 3
font.bold: true
}

StyledText {
Layout.alignment: Qt.AlignHCenter
animate: true
text: root.title
font.pointSize: Appearance.font.size.large
font.bold: true
}
}
Loading
Loading