Add Qt Bigscreen (QML/CMake), remove Tauri

Add a native Qt "Bigscreen" shell: CMakeLists, C++ entry (main.cpp, InputRouter), QML module (Theme, ShellWindow, views and components) and a Bigscreen/.gitignore; update top-level .gitignore and README with Qt build/run instructions. Remove the legacy Tauri/web prototype files (package.json, package-lock.json, src-tauri and many web assets) as part of the migration to the Qt/CMake-based shell.
This commit is contained in:
2026-05-23 21:19:24 +12:00
parent 627c52a5b7
commit f8632e40e7
102 changed files with 1123 additions and 17645 deletions
+59
View File
@@ -0,0 +1,59 @@
import QtQuick
import QtQuick.Layouts
import Nebula.Bigscreen
ColumnLayout {
id: root
property var homeTiles: [
{ label: "Library", meta: "Games and apps", icon: "📚", route: "library" },
{ label: "Settings", meta: "System controls", icon: "⚙", route: "settings" },
{ label: "Power", meta: "Sleep and sessions", icon: "⏻", route: "power" }
]
signal navigate(string route)
spacing: 28
Text {
text: "Home"
font: Theme.brandFont
color: Theme.textPrimary
Layout.leftMargin: 40
}
TileRail {
id: rail
Layout.fillWidth: true
tiles: root.homeTiles
onTileActivated: function(index) {
const route = root.homeTiles[index].route
if (route === "power") {
root.navigate("power")
} else {
root.navigate(route)
}
}
}
function handleInput(action) {
switch (action) {
case InputRouter.Left:
rail.moveFocus(-1)
break
case InputRouter.Right:
rail.moveFocus(1)
break
case InputRouter.Accept:
rail.activateFocused()
break
default:
break
}
}
function accentFocus() {
return rail.accentFocus
}
}
+99
View File
@@ -0,0 +1,99 @@
import QtQuick
import QtQuick.Layouts
import Nebula.Bigscreen
ColumnLayout {
id: root
signal goBack()
readonly property var entries: [
{ title: "Nebula Demo", meta: "Local • Ready", icon: "🎮" },
{ title: "Retro Runner", meta: "Wine • Installed", icon: "👾" },
{ title: "Media Hub", meta: "App • Installed", icon: "🎬" }
]
property int focusIndex: 0
spacing: 20
Text {
text: "Library"
font: Theme.brandFont
color: Theme.textPrimary
Layout.leftMargin: 40
}
Text {
text: "Mock entries for v0 — scanners and launchers come later."
font: Theme.metaFont
color: Theme.textMuted
Layout.leftMargin: 40
Layout.bottomMargin: 8
}
ListView {
id: list
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: 40
Layout.rightMargin: 40
clip: true
spacing: 12
model: root.entries
delegate: Rectangle {
width: list.width
height: 72
radius: 12
color: index === root.focusIndex ? "#22304A66" : Theme.backgroundPanel
border.color: index === root.focusIndex ? Theme.accentCyan : Theme.accentLine
border.width: index === root.focusIndex ? 2 : 1
RowLayout {
anchors.fill: parent
anchors.margins: 16
spacing: 16
Text {
text: modelData.icon
font.pixelSize: 28
}
ColumnLayout {
spacing: 2
Text {
text: modelData.title
font: Theme.titleFont
color: Theme.textPrimary
}
Text {
text: modelData.meta
font: Theme.metaFont
color: Theme.textMuted
}
}
}
}
}
function handleInput(action) {
switch (action) {
case InputRouter.Up:
focusIndex = Math.max(0, focusIndex - 1)
list.currentIndex = focusIndex
break
case InputRouter.Down:
focusIndex = Math.min(entries.length - 1, focusIndex + 1)
list.currentIndex = focusIndex
break
case InputRouter.Back:
root.goBack()
break
case InputRouter.Accept:
break
default:
break
}
}
}
+120
View File
@@ -0,0 +1,120 @@
import QtQuick
import QtQuick.Layouts
import Nebula.Bigscreen
ColumnLayout {
id: root
signal goBack()
readonly property var categories: [
"Network",
"Audio",
"Display",
"Controller",
"System"
]
property int categoryIndex: 0
property int itemIndex: 0
spacing: 20
Text {
text: "Settings"
font: Theme.brandFont
color: Theme.textPrimary
Layout.leftMargin: 40
}
Row {
Layout.leftMargin: 40
spacing: 16
Repeater {
model: root.categories
Rectangle {
height: 40
width: categoryLabel.implicitWidth + 24
radius: 8
color: index === root.categoryIndex ? "#22304A66" : "transparent"
border.color: index === root.categoryIndex ? Theme.accentCyan : "transparent"
border.width: index === root.categoryIndex ? 2 : 0
Text {
id: categoryLabel
anchors.centerIn: parent
text: modelData
font: Theme.bodyFont
color: index === root.categoryIndex ? Theme.accentCyan : Theme.textMuted
}
}
}
}
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.margins: 40
radius: 16
color: Theme.backgroundPanel
border.color: Theme.accentLine
ColumnLayout {
anchors.fill: parent
anchors.margins: 24
spacing: 12
Text {
text: root.categories[root.categoryIndex]
font: Theme.titleFont
color: Theme.textPrimary
}
Repeater {
model: 3
Rectangle {
Layout.fillWidth: true
height: 52
radius: 10
color: index === root.itemIndex ? "#22304A66" : Theme.backgroundMid
border.color: index === root.itemIndex ? Theme.accentCyan : Theme.accentLine
border.width: index === root.itemIndex ? 2 : 1
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 16
text: "Placeholder setting " + (index + 1)
font: Theme.bodyFont
color: Theme.textPrimary
}
}
}
}
}
function handleInput(action) {
switch (action) {
case InputRouter.Left:
categoryIndex = Math.max(0, categoryIndex - 1)
break
case InputRouter.Right:
categoryIndex = Math.min(categories.length - 1, categoryIndex + 1)
break
case InputRouter.Up:
itemIndex = Math.max(0, itemIndex - 1)
break
case InputRouter.Down:
itemIndex = Math.min(2, itemIndex + 1)
break
case InputRouter.Back:
root.goBack()
break
default:
break
}
}
}