10 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
This is a Quickshell-based desktop shell implementation with Material Design 3 dark theme. The shell provides a complete desktop environment experience with panels, widgets, and system integration services.
Architecture: Modular design with clean separation between UI components (Widgets), system services (Services), and shared utilities (Common).
Technology Stack
- QML (Qt Modeling Language) - Primary language for all UI components
- Quickshell Framework - QML-based framework for building desktop shells
- Qt/QtQuick - UI rendering and controls
- Qt5Compat - Graphical effects
- Wayland - Display server protocol
Development Commands
Since this is a Quickshell-based project without traditional build configuration files, development typically involves:
# Run the shell (requires Quickshell to be installed)
quickshell -p shell.qml
# Or use the shorthand
qs -p .
Architecture Overview
Modular Structure
The shell follows a clean modular architecture reduced from 4,830 lines to ~250 lines in shell.qml:
shell.qml # Main entry point (minimal orchestration)
├── Common/ # Shared resources
│ ├── Theme.qml # Material Design 3 theme singleton
│ └── Utilities.js # Shared utility functions
├── Services/ # System integration singletons
│ ├── AudioService.qml
│ ├── NetworkService.qml
│ ├── BrightnessService.qml
│ └── [9 total services]
└── Widgets/ # UI components
├── TopBar.qml
├── AppLauncher.qml
├── ControlCenterPopup.qml
└── [18 total widgets]
Component Organization
-
Shell Entry Point (
shell.qml)- Minimal orchestration layer (~250 lines)
- Imports and instantiates components
- Handles global state and property bindings
- Multi-monitor support using Quickshell's
Variants
-
Common/ - Shared resources
Theme.qml- Material Design 3 theme singleton with consistent colors, spacing, fontsUtilities.js- Shared functions for workspace parsing, notifications, menu handling
-
Services/ - System integration singletons
- Pattern: All services use
Singletontype withid: root - Independence: No cross-service dependencies
- Examples: AudioService, NetworkService, BrightnessService, WeatherService
- Services handle system commands, state management, and hardware integration
- Pattern: All services use
-
Widgets/ - Reusable UI components
- Full-screen components: AppLauncher, ClipboardHistory, ControlCenterPopup
- Panel components: TopBar, SystemTrayWidget, NotificationPopup
- Reusable controls: CustomSlider, WorkspaceSwitcher
- Each widget directory contains
qmldirfor module registration
Key Architectural Patterns
-
Singleton Services Pattern:
import QtQuick import Quickshell import Quickshell.Io pragma Singleton pragma ComponentBehavior: Bound Singleton { id: root property type value: defaultValue function performAction() { /* implementation */ } } -
Module Registration: Each directory contains
qmldirfile:singleton ServiceName 1.0 ServiceName.qml ComponentName 1.0 ComponentName.qml -
Smart Feature Detection: Services detect system capabilities:
property bool featureAvailable: false // Auto-hide UI elements when features unavailable visible: ServiceName.featureAvailable -
Property Bindings: Reactive UI updates through property binding
-
Material Design Theming: Consistent use of Theme singleton throughout
Important Components
- ControlCenterPopup: System controls (WiFi, Bluetooth, brightness, volume, night mode)
- AppLauncher: Full-featured app grid/list with 93+ applications, search, categories
- ClipboardHistory: Complete clipboard management with cliphist integration
- TopBar: Per-monitor panels with workspace switching, clock, system tray
- CustomSlider: Reusable enhanced slider with animations and smart detection
Code Conventions
QML Style Guidelines
-
Structure and Formatting:
- Use 4-space indentation
idshould be the first property- Properties before signal handlers before child components
- Prefer property bindings over imperative code
-
Naming Conventions:
- Services: Use
Singletontype withid: root - Components: Use descriptive names (e.g.,
CustomSlider,TopBar) - Properties: camelCase for properties, PascalCase for types
- Services: Use
-
Component Structure:
// For regular components Item { id: root property type name: value signal customSignal(type param) onSignal: { /* handler */ } Component { /* children */ } } // For services (singletons) Singleton { id: root property bool featureAvailable: false property type currentValue: defaultValue function performAction(param) { /* implementation */ } }
Import Guidelines
-
Standard Import Order:
import QtQuick import QtQuick.Controls // If needed import Quickshell import Quickshell.Widgets import Quickshell.Io // For Process, FileView import "../Common" // For Theme, utilities import "../Services" // For service access -
Service Dependencies:
- Services should NOT import other services
- Widgets can import and use services via property bindings
- Use
Theme.propertyNamefor consistent styling
Component Development Patterns
-
Smart Feature Detection:
// In services - detect capabilities property bool brightnessAvailable: false // In widgets - adapt UI accordingly CustomSlider { visible: BrightnessService.brightnessAvailable enabled: BrightnessService.brightnessAvailable value: BrightnessService.brightnessLevel } -
Reusable Components:
- Create reusable widgets for common patterns (like CustomSlider)
- Use configurable properties for different use cases
- Include proper signal handling with unique names (avoid
valueChanged)
-
Service Integration:
- Services expose properties and functions
- Widgets bind to service properties for reactive updates
- Use service functions for actions:
ServiceName.performAction(value)
Error Handling and Debugging
-
Console Logging:
// Use appropriate log levels console.log("Info message") // General info console.warn("Warning message") // Warnings console.error("Error message") // Errors // Include context in service operations onExited: (exitCode) => { if (exitCode !== 0) { console.warn("Service failed:", serviceName, "exit code:", exitCode) } } -
Graceful Degradation:
- Always check feature availability before showing UI
- Provide fallbacks for missing system tools
- Use
visibleandenabledproperties appropriately
Multi-Monitor Support
The shell uses Quickshell's Variants pattern for multi-monitor support:
- Each connected monitor gets its own top bar instance
- Workspace switchers are per-display and Niri-aware
- Monitors are automatically detected by screen name (DP-1, DP-2, etc.)
- Workspaces are dynamically synchronized with Niri's per-output workspaces
Common Development Tasks
Testing and Validation
When modifying the shell:
- Test changes:
qs -p .(automatic reload on file changes) - Performance: Ensure animations remain smooth (60 FPS target)
- Theming: Use
Theme.propertyNamefor Material Design 3 consistency - Wayland compatibility: Test on Wayland session
- Multi-monitor: Verify behavior with multiple displays
- Feature detection: Test on systems with/without required tools
Adding New Widgets
-
Create component:
# Create new widget file touch Widgets/NewWidget.qml -
Register in qmldir:
# Add to Widgets/qmldir NewWidget 1.0 NewWidget.qml -
Follow widget patterns:
- Use
Theme.propertyNamefor styling - Import
"../Common"and"../Services"as needed - Bind to service properties for reactive updates
- Consider per-screen vs global behavior
- Use
-
Integration in shell.qml:
NewWidget { id: newWidget // Configure properties }
Adding New Services
-
Create service:
// Services/NewService.qml import QtQuick import Quickshell import Quickshell.Io pragma Singleton pragma ComponentBehavior: Bound Singleton { id: root property bool featureAvailable: false property type currentValue: defaultValue function performAction(param) { // Implementation } } -
Register in qmldir:
# Add to Services/qmldir singleton NewService 1.0 NewService.qml -
Use in widgets:
// In widget files property alias serviceValue: NewService.currentValue SomeControl { visible: NewService.featureAvailable enabled: NewService.featureAvailable onTriggered: NewService.performAction(value) }
Debugging Common Issues
- Import errors: Check
qmldirregistration and import paths - Singleton conflicts: Ensure services use
Singletontype withid: root - Property binding issues: Use property aliases for reactive updates
- Process failures: Check system tool availability and command syntax
- Theme inconsistencies: Always use
Theme.propertyNameinstead of hardcoded values
Best Practices Summary
- Modularity: Keep components focused and independent
- Reusability: Create reusable components for common patterns
- Responsiveness: Use property bindings for reactive UI
- Robustness: Implement feature detection and graceful degradation
- Consistency: Follow Material Design 3 principles via Theme singleton
- Performance: Minimize expensive operations and use appropriate data structures