Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
170 commits
Select commit Hold shift + click to select a range
022b2cb
feat(desktop-qt): add the Node desktop host for the Qt shell
olafura Aug 26, 2026
c2de49a
feat(desktop-qt): Qt/QML shell that hosts the web app
olafura Aug 26, 2026
2ec89fa
feat(desktop-qt): dev loop script and dev:qt
olafura Aug 26, 2026
b732cd1
feat(desktop-qt): example theme.json and shell.qml
olafura Aug 26, 2026
c456590
docs(internals): describe the Qt shell
olafura Aug 26, 2026
1cb5223
feat(contracts): shell protocol for native hosts
olafura Aug 26, 2026
34d8337
refactor(web): share the sidebar's thread partition and project grouping
olafura Aug 26, 2026
08df852
feat(web): publish the sidebar to the Qt shell and hide the HTML one …
olafura Aug 26, 2026
b602356
feat(desktop-qt): QML sidebar brick
olafura Aug 26, 2026
8075f12
docs(internals): describe the Qt shell sidebar projection
olafura Aug 26, 2026
4eb6956
feat(contracts): composer state and actions for native shells
olafura Aug 26, 2026
9e417e1
feat(web): publish the composer to the Qt shell and hide the HTML edi…
olafura Aug 26, 2026
fbc1100
feat(desktop-qt): QML composer brick
olafura Aug 26, 2026
3b03397
docs(internals): describe the Qt shell composer projection
olafura Aug 26, 2026
e914bd8
feat(contracts): right panel state and actions for native shells
olafura Aug 26, 2026
78a448a
feat(web): converge panel stores across documents under the Qt shell
olafura Aug 26, 2026
def5075
feat(web): embed route and right panel projection for the Qt shell
olafura Aug 26, 2026
f43977d
feat(desktop-qt): right panel brick with an embedded web surface
olafura Aug 26, 2026
a323861
docs(internals): describe the Qt shell right panel and embed route
olafura Aug 26, 2026
7a3ca26
feat(desktop-qt): embed documents follow the primary's thread in place
olafura Aug 26, 2026
dcdd031
feat(contracts): workspace state and actions for native shells
olafura Aug 26, 2026
12949c8
feat(web): publish the workspace strip to the Qt shell
olafura Aug 26, 2026
4be6c40
feat(desktop-qt): workspace strip brick
olafura Aug 26, 2026
7b19b58
docs(internals): describe the Qt shell workspace projection
olafura Aug 26, 2026
930ecbc
feat(contracts): settings navigation state and actions for native shells
olafura Aug 26, 2026
270ad97
feat(web): publish settings navigation to the Qt shell
olafura Aug 26, 2026
c85658d
feat(desktop-qt): settings navigation brick
olafura Aug 26, 2026
3f0d980
docs(internals): describe the Qt shell settings projection
olafura Aug 26, 2026
326f631
refactor(web): extract the branch selector's switching logic into a hook
olafura Aug 26, 2026
5711679
feat(contracts): branch list and switching actions for native shells
olafura Aug 26, 2026
fa473b2
feat(web): native branch switching for the Qt shell
olafura Aug 26, 2026
30dff95
feat(desktop-qt): branch picker in the workspace strip
olafura Aug 26, 2026
b1ad6af
docs(internals): describe native branch switching
olafura Aug 26, 2026
e98c3dc
feat(contracts): composer suggestions for native shells
olafura Aug 26, 2026
4ce4c71
feat(web): @file, $skill and /command suggestions for the Qt shell
olafura Aug 26, 2026
26b39fc
feat(desktop-qt): suggestion popup in the composer
olafura Aug 26, 2026
9cd0a64
docs(internals): describe composer suggestions in the Qt shell
olafura Aug 26, 2026
1aa48fb
feat(contracts): page theme state for native shells
olafura Aug 26, 2026
31ff2ad
feat(web): publish the resolved page theme to the Qt shell
olafura Aug 26, 2026
4cdce46
feat(desktop-qt): page theme by default and themed controls
olafura Aug 26, 2026
827cf89
feat(contracts): notifications for native shells
olafura Aug 26, 2026
09c9e15
feat(web): mirror toasts to the Qt shell
olafura Aug 26, 2026
6a7e66a
feat(desktop-qt): native notifications
olafura Aug 26, 2026
84f3887
feat(contracts): context menus, thread title menu and rename for nati…
olafura Aug 26, 2026
b504cea
feat(web): native context menus, thread title menu and rename under t…
olafura Aug 26, 2026
18912fc
feat(desktop-qt): context menu host, title menu and inline rename
olafura Aug 26, 2026
c7f0bfa
feat(contracts): composer attachments and terminal contexts for nativ…
olafura Aug 26, 2026
b841354
feat(web): attachments and terminal selections from the Qt shell
olafura Aug 26, 2026
b5d15cc
feat(desktop-qt): image attachments and context chips in the composer
olafura Aug 26, 2026
9c21438
refactor(web): extract the git control's runner and model into useGit…
olafura Aug 26, 2026
84f5725
feat(contracts): git control state and actions for native shells
olafura Aug 26, 2026
6cbe5d2
feat(web): native git control under the Qt shell
olafura Aug 26, 2026
c97ae4e
feat(desktop-qt): native git split button, commit and default-branch …
olafura Aug 26, 2026
d9320b0
feat(desktop-qt): example rices
olafura Aug 26, 2026
57680a9
ci(desktop-qt): build and package on Linux and macOS
olafura Aug 26, 2026
e7379f6
docs(desktop-qt): theme sync, notifications, menus, git and packaging
olafura Aug 26, 2026
66551c4
fix(desktop-qt): keep the rice under T3 home
olafura Aug 26, 2026
dad8865
feat(desktop-qt): native window blur on macOS and a drawn chevron
olafura Aug 26, 2026
0231cf9
fix(desktop-qt): real glass on macOS
olafura Aug 27, 2026
e67f480
fix(web): toasts mirrored to the Qt shell can be dismissed
olafura Aug 27, 2026
c3ee728
feat: animated sidebar collapse for the Qt shell
olafura Aug 27, 2026
455d6d0
style(desktop-qt): spacing pass and motion on the bricks
olafura Aug 27, 2026
fadfd69
fix(desktop-qt): dev:qt shows why pairing failed
olafura Aug 27, 2026
60c866f
chore: dev:qt runs the Qt dev script directly
olafura Aug 27, 2026
2582a63
feat(desktop-qt): dev:qt takes --home-dir and forwards shell flags
olafura Aug 27, 2026
1f085d9
fix(desktop-qt): keep the last shell alive when a reload fails
olafura Aug 27, 2026
2e6898c
fix(desktop-qt): say so when the desktop host dies after startup
olafura Aug 27, 2026
7a590a7
fix(desktop-qt): dev:qt refuses to pair against the live install
olafura Aug 27, 2026
695eec9
fix(desktop-qt): Enter in the composer no longer drops on a stale can…
olafura Aug 27, 2026
b18bcef
fix(web): shell title menu no longer reopens on unrelated rerenders
olafura Aug 27, 2026
79524d4
feat(web): shell branch picker checks out PR references
olafura Aug 27, 2026
74b59c5
fix(web): toasts mirrored to the Qt shell auto-dismiss
olafura Aug 27, 2026
b47db04
perf(shell): skip republishing unchanged state to the Qt shell
olafura Aug 27, 2026
4e5f462
fix(web): a stale project key no longer creates the thread elsewhere
olafura Aug 27, 2026
e4f91f6
fix(web): the shell embed document no longer persists UI state
olafura Aug 27, 2026
5ca85fb
fix(desktop-qt): scripted runs fail when the page does not load
olafura Aug 27, 2026
85d557a
fix(web): git init failures surface a toast on the Qt shell path
olafura Aug 27, 2026
72249b0
fix(desktop-qt): right panel document survives closing and route changes
olafura Aug 27, 2026
1c15955
fix(web): sidebar rename waits for the thread view instead of 150ms
olafura Aug 27, 2026
aa42456
fix(web): a malformed shell attachment no longer breaks the action ha…
olafura Aug 27, 2026
0b6e783
fix(web): shell-hosted composer keeps its frame for the shoulder tabs
olafura Aug 27, 2026
964800b
feat(desktop-qt): Sidebar brick can hide its scope picker and footer
olafura Aug 27, 2026
7c652c9
feat(desktop-qt): rosé dashboard rice with a widget drawer
olafura Aug 27, 2026
11feaaf
feat(desktop-qt): lucide icons drawn as shapes
olafura Aug 27, 2026
28e9ef4
feat(desktop-qt): sidebar with brand band and scope rows
olafura Aug 27, 2026
08c639b
feat(desktop-qt): header strip with pills and panel toggle
olafura Aug 27, 2026
9aa3baa
feat(desktop-qt): composer card with checkout strip
olafura Aug 27, 2026
ace280d
docs(desktop-qt): describe the brick layers and default shell
olafura Aug 27, 2026
47823f6
feat(desktop-qt): ShellWindow and ShellCard bricks
olafura Sep 1, 2026
e864fe6
feat(desktop-qt): traffic-light window controls
olafura Sep 1, 2026
8ba5b94
fix(desktop-qt): prefer an installed font family from the theme stack
olafura Sep 1, 2026
503ce68
feat(desktop-qt): more lucide icons
olafura Sep 1, 2026
dceb16f
feat(desktop-qt): minimal example on the web palette
olafura Sep 1, 2026
5d22556
feat(desktop-qt): glass example shaped like a mac window
olafura Sep 1, 2026
025cbab
feat(desktop-qt): terminal example picks up the terminal's colours
olafura Sep 1, 2026
573ed58
refactor(desktop-qt): dashboard example on the shared bricks
olafura Sep 1, 2026
6d8dd70
feat(desktop-qt): cat lottie and motion pass for the dashboard
olafura Sep 1, 2026
f23a8e1
docs(desktop-qt): examples README and brick docs
olafura Sep 1, 2026
4616a79
fix(web): embed route follows the primary surface's thread
olafura Sep 2, 2026
1e38dd0
fix(web): thread rename reports a failure once
olafura Sep 2, 2026
bc9715d
chore(web): drop incidental diffs against main
olafura Sep 2, 2026
6baeddb
test(web): cover sidebar partitioning
olafura Sep 2, 2026
6c571c7
perf(desktop-qt): freeze the hidden panel and stop resizing the web v…
olafura Sep 2, 2026
7f65907
feat(desktop-qt): pages get the async clipboard
olafura Sep 2, 2026
2491c29
refactor(contracts): serve the shell contract from a subpath export
olafura Sep 2, 2026
b0362ae
refactor(web): lazy-load the shell bridges and decode actions in one …
olafura Sep 2, 2026
93d0de4
feat(desktop-qt): browser profile under T3 home with a disk cache
olafura Sep 2, 2026
74f24ad
perf(desktop-qt): keep the state map off the web channel
olafura Sep 2, 2026
8c981fc
docs(desktop-qt): web engine, channel and bridge loading
olafura Sep 2, 2026
da73bcf
fix(desktop-qt): centre a lone chevron or icon in ShellButton
olafura Sep 2, 2026
9aac7bb
fix(desktop-qt): dashboard project card grows with its chips
olafura Sep 2, 2026
e6c4ab8
feat(desktop-qt): dashboard rice drops the notch tabs
olafura Sep 2, 2026
953a941
feat(desktop-qt): terminal theme generator as vp run theme:qt
olafura Sep 2, 2026
2f5bcc5
feat(desktop-qt): terminal rice status line and spacing
olafura Sep 2, 2026
f6ce728
fix(desktop-qt): inject the shell theme before first paint
olafura Sep 2, 2026
159ccd6
feat(desktop-qt): bolder terminal theme and powerline status line
olafura Sep 2, 2026
794c6aa
feat(desktop-qt): put the palette to work in the sidebar
olafura Sep 2, 2026
2a9d6db
feat(desktop-qt): carry the palette into the page roles
olafura Sep 2, 2026
33f48bd
feat(desktop-qt): terminal theme inks text with the bright-white slot
olafura Sep 2, 2026
6f515c0
feat(desktop-qt): terminal rice for a tiling desktop, web wordmark brick
olafura Sep 2, 2026
cb7d694
feat(desktop-qt): terminal drawer toggle in the header strip
olafura Sep 2, 2026
966afa3
feat(desktop-qt): terminal drawer as a shell-placed surface under the…
olafura Sep 2, 2026
b1d986c
feat(web): shell sidebar publishes row actions, woke state and keybin…
olafura Sep 2, 2026
1b8c5ff
feat(desktop-qt): sidebar row actions, status states and keyboard nav…
olafura Sep 2, 2026
9da81a6
feat(desktop-qt): scripted --key presses for shell tests
olafura Sep 2, 2026
0efaa96
fix(web): shell embeds forward page keybindings to the primary document
olafura Sep 2, 2026
56b0eed
fix(web): resolve shell theme color variables
olafura Sep 2, 2026
d6e58bf
fix(desktop-qt): synchronize native draft and thread state
olafura Sep 2, 2026
a7ff5d3
test(desktop-qt): use the workspace test entrypoint
olafura Sep 2, 2026
0bbce8f
fix(desktop-qt): ship a runnable release runtime
olafura Sep 2, 2026
59981ed
fix(desktop-qt): reapply macOS blur on theme changes
olafura Sep 2, 2026
5cf9af9
chore(desktop-qt): satisfy script lint rules
olafura Sep 2, 2026
2e5e1f6
refactor(web): reuse canonical scoped keys
olafura Sep 2, 2026
6e1c72a
refactor(web): route shell menus through local API
olafura Sep 2, 2026
e8a8106
refactor(web): constrain projected theme roles
olafura Sep 2, 2026
57ed284
refactor(desktop-qt): use Node OS runtime queries
olafura Sep 2, 2026
321214d
refactor(desktop-qt): use a single-shot page load hook
olafura Sep 2, 2026
f69b9b2
refactor(desktop-qt): remove dead Qt location lookup
olafura Sep 2, 2026
e68896f
Revert "refactor(web): route shell menus through local API"
olafura Sep 2, 2026
4ed9d19
fix(desktop-qt): keep composer edits with their target
olafura Sep 2, 2026
12cc5a6
fix(shell): isolate native context menu requests
olafura Sep 2, 2026
b81539c
fix(desktop-qt): share the selected home with the server
olafura Sep 2, 2026
3c3d41e
fix(desktop-qt): bundle Node with release packages
olafura Sep 2, 2026
3b0e7fe
ci(desktop-qt): rebuild for every package input
olafura Sep 2, 2026
e2328df
fix(desktop-qt): terminal drawer in every example rice
olafura Sep 4, 2026
2e5d4a6
feat(desktop-qt): round web surfaces for carded rices
olafura Sep 4, 2026
5436d1c
fix(desktop-qt): dashboard rice contrast, composer, and rounded surfaces
olafura Sep 4, 2026
24a2e7c
fix(desktop-qt): reconcile web integration after upstream rebase
olafura Sep 7, 2026
ddae71e
fix(desktop-qt): preserve singleton engine across hot reloads
olafura Sep 7, 2026
bfa9f4c
fix(desktop-qt): ignore superseded composer text echoes
olafura Sep 7, 2026
6ef0628
refactor(web): share thread parking workflow across sidebars
olafura Sep 7, 2026
59ba6e6
refactor(desktop-qt): hand theme override ownership to the web page
olafura Sep 7, 2026
a9c5d9a
refactor(web): share thread terminals without mounting conversation s…
olafura Sep 7, 2026
4b5f259
fix(desktop-qt): center button contents and smooth light-theme hover
olafura Sep 7, 2026
7ed7153
fix(desktop-qt): preserve sidebar hover during live updates
olafura Sep 7, 2026
e29f390
fix(web): give terminal contents consistent edge padding
olafura Sep 7, 2026
e0ac503
fix(desktop-qt): avoid premature header title truncation
olafura Sep 7, 2026
a374d18
fix(desktop-qt): keep dashboard widgets inside a scrollable grid
olafura Sep 7, 2026
189f425
fix(desktop-qt): inset notification accents within rounded corners
olafura Sep 7, 2026
ed3ebba
fix(desktop-qt): recover from invalid shell and theme reloads
olafura Sep 7, 2026
69619b5
fix(web): align native shell controls with page state
olafura Sep 7, 2026
6369167
fix(web): roll back rejected terminal allocations
olafura Sep 7, 2026
be7243e
fix(desktop-qt): complete native keyboard interactions
olafura Sep 7, 2026
91a9f5e
fix(desktop-qt): scope clipboard permissions to the app origin
olafura Sep 7, 2026
e352a4d
fix(web): preserve nested native context menu actions
olafura Sep 7, 2026
40ecd12
fix(desktop-qt): make release tooling reproducible
olafura Sep 7, 2026
83c7e05
fix(desktop-qt): restore legacy page theme on override removal
olafura Sep 7, 2026
65bccc9
fix(web): retry git toast actions with current branch state
olafura Sep 7, 2026
85fff06
test(web): cover retained shell embed navigation
olafura Sep 7, 2026
e770f4a
test(web): use the panel route surface in embed coverage
olafura Sep 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions .github/workflows/desktop-qt.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
name: desktop-qt

on:
push:
paths:
- "apps/desktop-qt/**"
- "apps/server/**"
- "apps/web/**"
- "packages/**"
- "patches/**"
- "assets/prod/black-universal-1024.png"
- "scripts/lib/cli-external-packages.ts"
- "package.json"
- "pnpm-lock.yaml"
- "pnpm-workspace.yaml"
- "vite.config.ts"
- ".github/workflows/desktop-qt.yml"
pull_request:
paths:
- "apps/desktop-qt/**"
- "apps/server/**"
- "apps/web/**"
- "packages/**"
- "patches/**"
- "assets/prod/black-universal-1024.png"
- "scripts/lib/cli-external-packages.ts"
- "package.json"
- "pnpm-lock.yaml"
- "pnpm-workspace.yaml"
- "vite.config.ts"
- ".github/workflows/desktop-qt.yml"
workflow_dispatch:

permissions:
contents: read

jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
qt_host: linux
qt_arch: linux_gcc_64
- os: macos-15
qt_host: mac
qt_arch: clang_64
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
Comment thread
coderabbitai[bot] marked this conversation as resolved.
with:
persist-credentials: false

- name: Setup Vite+
uses: voidzero-dev/setup-vp@v1
with:
node-version-file: package.json
cache: true
run-install: |
args:
- --filter=t3...

# Official Qt binaries on every platform so WebEngine is always present
# (distro packages often ship without it).
- uses: jurplel/install-qt-action@v4
with:
version: "6.9.*"
host: ${{ matrix.qt_host }}
arch: ${{ matrix.qt_arch }}
modules: qtwebengine qtwebchannel qtpositioning
cache: true

- name: Install build tools (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y ninja-build libgl1-mesa-dev libxkbcommon-dev libfuse2 \
libxcb-cursor0 libnss3 libxcomposite1 libxdamage1 libxrandr2 libasound2t64

- name: Install build tools (macOS)
if: runner.os == 'macOS'
run: brew install ninja

- name: Configure
run: >
cmake -S apps/desktop-qt -B apps/desktop-qt/build/release -G Ninja
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_PREFIX_PATH="${{ env.QT_ROOT_DIR }}"

- name: Build
run: cmake --build apps/desktop-qt/build/release

- name: Build server runtime
run: vp run --filter t3 build

- name: Test QML
run: node apps/desktop-qt/scripts/test-qml.mjs

- name: Package (Linux AppImage)
if: runner.os == 'Linux'
run: apps/desktop-qt/scripts/package-linux.sh apps/desktop-qt/build/release

- name: Package (macOS app bundle)
if: runner.os == 'macOS'
run: |
node apps/desktop-qt/scripts/stage-runtime.mjs apps/desktop-qt/build/release/t3code-qt.app/Contents/Resources/t3code
"${QT_ROOT_DIR}/bin/macdeployqt" apps/desktop-qt/build/release/t3code-qt.app -qmldir=apps/desktop-qt/qml
ditto -c -k --keepParent apps/desktop-qt/build/release/t3code-qt.app apps/desktop-qt/build/release/t3code-qt-macos.zip

- uses: actions/upload-artifact@v4
with:
name: t3code-qt-${{ matrix.os }}
path: |
apps/desktop-qt/build/release/*.AppImage
apps/desktop-qt/build/release/*.zip
if-no-files-found: error
120 changes: 120 additions & 0 deletions apps/desktop-qt/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
cmake_minimum_required(VERSION 3.21)

project(t3code-qt VERSION 0.0.1 LANGUAGES CXX)
Comment thread
coderabbitai[bot] marked this conversation as resolved.

if(APPLE)
enable_language(OBJCXX)
endif()

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)

find_package(Qt6 6.9 REQUIRED COMPONENTS Core Gui GuiPrivate Quick WebEngineQuick WebChannel)
qt_standard_project_setup(REQUIRES 6.9)
qt_policy(SET QTP0001 NEW)

# Where the QML bricks live on disk. Non-release builds load them from here so
# edits hot-reload without a rebuild; release builds only use the compiled-in
# copies. T3_QML_SOURCE_DIR="" disables disk loading for any build type.
if(NOT DEFINED T3_QML_SOURCE_DIR)
set(T3_QML_SOURCE_DIR "$<IF:$<CONFIG:Release>,,${CMAKE_CURRENT_SOURCE_DIR}/qml>")
endif()

# The Node desktop host entry. In-repo builds point at the TypeScript source.
# Release builds resolve an installed path relative to the executable.
if(NOT DEFINED T3_HOST_ENTRY)
if(APPLE)
set(_t3_installed_host "../Resources/t3code/host/main.ts")
else()
set(_t3_installed_host "../share/t3code/host/main.ts")
endif()
set(T3_HOST_ENTRY "$<IF:$<CONFIG:Release>,${_t3_installed_host},${CMAKE_CURRENT_SOURCE_DIR}/host/main.ts>")
endif()

# Release packages carry the same Node executable that installed their native
# dependencies. Development builds keep using the command from PATH.
if(NOT DEFINED T3_NODE_ENTRY)
if(APPLE)
set(_t3_installed_node "../Resources/t3code/bin/node")
elseif(WIN32)
set(_t3_installed_node "../share/t3code/bin/node.exe")
else()
set(_t3_installed_node "../share/t3code/bin/node")
endif()
set(T3_NODE_ENTRY "$<IF:$<CONFIG:Release>,${_t3_installed_node},node>")
endif()

# qwebchannel.js is the browser half of Qt WebChannel. Qt installs it as data
# (share/qt6/webchannel); bundling it makes the injected script independent of
# whether the runtime Qt exposes it as a qrc resource.
get_filename_component(_qt_prefix "${QT6_INSTALL_PREFIX}" ABSOLUTE)
find_file(T3_QWEBCHANNEL_JS qwebchannel.js
HINTS
"${_qt_prefix}/${QT6_INSTALL_DATA}/webchannel"
"${_qt_prefix}/share/qt6/webchannel"
"${_qt_prefix}/share/qt/webchannel"
"${_qt_prefix}/../qtwebchannel/share/qt6/webchannel"
)

qt_add_executable(t3code-qt
src/main.cpp
src/BackendProcess.cpp
src/BackendProcess.h
src/ShellBridge.cpp
src/ShellBridge.h
src/ShellRuntime.cpp
src/ShellRuntime.h
src/ThemeStore.cpp
src/ThemeStore.h
src/WebProfile.cpp
src/WebProfile.h
src/PlatformWindow.h
)

if(T3_QWEBCHANNEL_JS)
set_source_files_properties("${T3_QWEBCHANNEL_JS}" PROPERTIES QT_RESOURCE_ALIAS "qwebchannel.js")
qt_add_resources(t3code-qt "t3_webchannel" PREFIX "/t3" FILES "${T3_QWEBCHANNEL_JS}")
target_compile_definitions(t3code-qt PRIVATE T3_WEBCHANNEL_SCRIPT_URL="qrc:/t3/qwebchannel.js")
else()
message(STATUS "qwebchannel.js not found next to Qt; relying on qrc:///qtwebchannel/qwebchannel.js at runtime")
target_compile_definitions(t3code-qt PRIVATE T3_WEBCHANNEL_SCRIPT_URL="qrc:///qtwebchannel/qwebchannel.js")
endif()

target_compile_definitions(t3code-qt PRIVATE
T3_QML_SOURCE_DIR="${T3_QML_SOURCE_DIR}"
T3_HOST_ENTRY="${T3_HOST_ENTRY}"
T3_NODE_ENTRY="${T3_NODE_ENTRY}"
T3_APP_VERSION="${PROJECT_VERSION}"
)

if(APPLE)
target_sources(t3code-qt PRIVATE src/PlatformWindow.mm)
target_link_libraries(t3code-qt PRIVATE "-framework AppKit")
else()
target_sources(t3code-qt PRIVATE src/PlatformWindow.cpp)
endif()

add_subdirectory(qml/T3/Bricks)

target_link_libraries(t3code-qt PRIVATE
Qt6::Core
Qt6::Gui
Qt6::GuiPrivate
Qt6::Quick
Qt6::WebEngineQuick
Qt6::WebChannel
t3bricksplugin
)

set_target_properties(t3code-qt PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_GUI_IDENTIFIER "codes.t3.desktop-qt"
MACOSX_BUNDLE_BUNDLE_NAME "T3 Code"
WIN32_EXECUTABLE TRUE
)

install(TARGETS t3code-qt
BUNDLE DESTINATION .
RUNTIME DESTINATION bin
)
25 changes: 25 additions & 0 deletions apps/desktop-qt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# @t3tools/desktop-qt

Qt/QML shell for T3 Code. Hosts the web app in a `WebEngineView` and lets the
window chrome be rearranged and themed from `~/.t3/shell/`.

Architecture, setup, and the QML/theme contracts: `docs/internals/desktop-qt.md`.

```sh
vp run dev # terminal 1: server + web
vp run dev:qt # terminal 2: build the shell, pair, launch
```

Focused native checks use temporary data and run offscreen:

```sh
vp run --filter @t3tools/desktop-qt test:qml
cmake -S apps/desktop-qt/tests/native -B apps/desktop-qt/build/tests/native
cmake --build apps/desktop-qt/build/tests/native
ctest --test-dir apps/desktop-qt/build/tests/native --output-on-failure
```

`ShellRuntime` covers reload and theme ownership. `ShellExamples` loads all
four examples at 640, 1000, and 1400 pixels, checking header text and dashboard
card bounds, long branch names, clipped icons, and scrolling to the last card. It uses a local
view-model fixture and a blank web page; no running server or pairing is needed.
40 changes: 40 additions & 0 deletions apps/desktop-qt/examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Shell examples

Each folder is a complete rice: a `shell.qml` layout composed from the
`T3.Bricks` module and a `theme.json` in the web app's theme format (plus the
shell-only `window`, `radius` and `fonts` keys). Copy one into your config dir
and the app reloads on save:

```sh
cp examples/glass/*.* ~/.t3/shell/
```

| Example | Idea |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `minimal` | The default layout with the title bar moved to the bottom, on the web app's own dark palette (`theme.json` here is the page's default theme, so it is the one to copy when a rice should start from stock colours). |
| `dashboard` | Rosé light theme, an icon rail that also carries settings, and a Dashboard button that pulls a widget drawer over the page: today, the month, the open workspace, thread meters, and the agent, with a cat at play (a Lottie animation; needs the Qt Lottie module, `qt6-lottie` on Arch, and shows the agent's initial without it). |
| `glass` | The shape of a Mac app: one rounded window with a hairline edge, traffic lights, a translucent sidebar for the compositor to blur behind, and a unified toolbar over an opaque content column. |
| `terminal` | Status line with the wordmark, a prompt mark, counts and the model; mono type, sharp corners. Made for a tiling desktop such as Omarchy, with flags at the top of `shell.qml` for a clock, window buttons and a chip of the palette's sixteen colours. Its `theme.json` is Tokyo Night as `vp run theme:qt` writes it from a terminal in those colours. |

Pick up your own terminal's colours (it asks the terminal for its palette and
writes `theme.json` into the shell directory, `~/.t3/shell` by default):

```sh
vp run theme:qt
vp run theme:qt ~/.t3/shell
```

What you can reach from `shell.qml`: `ShellWindow` as the root (window
colour, opacity and frame from the theme, `sidebarCollapsed` and
`settingsActive` from the page, the error overlay and the page's window
commands built in), the bricks (`TitleBar`, `Sidebar`, `SettingsNav`,
`Workspace`, `GitActions`, `WebSurface`, `Composer`, `RightPanel`, `TerminalDrawer`,
`Notifications`), the themed controls (`ShellCard`, `ShellButton`,
`ShellComboBox`, `ShellTextField`, `ShellMenu`, `ShellMenuItem`, `ShellIcon`,
`WindowControls`), and the `T3.Shell` singletons: `Shell.state.<key>` for
everything the page publishes, `Shell.dispatch(action, payload)` to act,
`Theme.color(role, fallback)` / `Theme.radius` / `Theme.fontUi` /
`Theme.fontMono`, and `Runtime.reload()`.

A broken `shell.qml` never locks you out: the built-in shell takes over with
the error shown in an overlay.
20 changes: 20 additions & 0 deletions apps/desktop-qt/examples/dashboard/CatPlaying.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import QtQuick
import Qt.labs.lottieqt

// The cat at play (cat-playing.json), fitted into whatever box it is given.
// Qt Lottie paints at the frame size the file declares, so the painter is
// scaled instead of the item. Needs the Qt Lottie module (qt6-lottie); the
// dashboard falls back to the agent's initial when the import fails.
LottieAnimation {
id: cat

// The file's frame (its "w" and "h"); the host resizes the item.
readonly property size frame: Qt.size(1070, 456)

implicitHeight: width * frame.height / frame.width
source: "cat-playing.json"
autoPlay: true
loops: LottieAnimation.Infinite
quality: LottieAnimation.HighQuality
contentsScale: Math.min(width / frame.width, height / frame.height)
}
1 change: 1 addition & 0 deletions apps/desktop-qt/examples/dashboard/cat-playing.json

Large diffs are not rendered by default.

Loading
Loading