Documentation Index
Fetch the complete documentation index at: https://mintlify.com/FALAK097/typesteps/llms.txt
Use this file to discover all available pages before exploring further.
Thank you for your interest in contributing to TypeSteps! This guide will help you get started.
Code of Conduct
Be respectful, professional, and constructive. TypeSteps is a community project focused on privacy and user experience.
Ways to Contribute
Report Issues
Found a bug or have a feature request? Open an issue on GitHub:
- Check existing issues to avoid duplicates
- Use descriptive titles
- Include:
- macOS version
- Xcode version (if building from source)
- Steps to reproduce
- Expected vs actual behavior
- Screenshots if applicable
Submit Pull Requests
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature-name
- Make your changes following our code standards
- Test thoroughly
- Commit with clear messages
- Push to your fork
- Open a pull request
Code Standards
Swift Style
Follow Swift best practices:
// Good: Clear naming, proper spacing
func incrementCount(for date: Date = Date(),
appName: String? = nil,
bundleId: String? = nil) {
let dayString = dateFormatter.string(from: date)
dailyStats[dayString] = (dailyStats[dayString] ?? 0) + 1
saveStats()
}
// Bad: Unclear naming, poor spacing
func inc(d:Date=Date(),a:String?=nil,b:String?=nil){
let ds=df.string(from:d)
ds_[ds]=(ds_[ds] ?? 0)+1
sv()
}
Naming Conventions
- Classes/Structs: PascalCase (
StorageManager, KeystrokeListener)
- Functions/Variables: camelCase (
incrementCount, isAuthorized)
- Constants: camelCase with descriptive names (
statsKey, hourlyKey)
- Published properties: camelCase (
dailyStats, isPaused)
SwiftUI Patterns
Use StateObject for singletons:
@StateObject private var storage = StorageManager.shared
@StateObject private var listener = KeystrokeListener.shared
Use AppStorage for persisted settings:
@AppStorage("daily_goal") private var dailyGoal = 5000
@AppStorage("app_theme") private var appTheme = 0
Keep views lightweight:
// Good: Extract complex logic to computed properties
private var chartData: [ActivityPoint] {
let rawData: [(label: String, count: Int)]
switch selectedTab {
case 0: rawData = storage.getTodayHourly()
case 1: rawData = storage.getLastSevenDays()
case 2: rawData = storage.getLastSixMonths()
default: rawData = []
}
return rawData.map { ActivityPoint(label: $0.label, count: $0.count) }
}
// Then use in view
Chart {
ForEach(chartData) { point in
BarMark(x: .value("L", point.label), y: .value("C", point.count))
}
}
Documentation
Add comments for complex logic:
// Xcode titles often look like "ProjectName — FileName.swift"
if appName == "Xcode" {
let components = title.components(separatedBy: " — ")
return components.first
}
Document public APIs:
/// Increments the keystroke count for the current date and app
/// - Parameters:
/// - date: The date to increment (defaults to now)
/// - appName: Name of the active application
/// - bundleId: Bundle identifier for the app
/// - projectName: Extracted project name if available
func incrementCount(for date: Date = Date(),
appName: String? = nil,
bundleId: String? = nil,
projectName: String? = nil)
File Organization
Keep related code together:
Sources/
├── TypeStepsApp.swift # Main app entry point
├── Models.swift # Data models
├── KeystrokeListener.swift # Event monitoring
├── StorageManager.swift # Data persistence
├── WakaTimeManager.swift # WakaTime integration
├── DashboardView.swift # Main UI
├── WelcomeView.swift # Onboarding UI
└── Theme.swift # Theme definitions
Architecture Principles
Separation of Concerns
- Models: Data structures only
- Managers: Business logic and state
- Views: UI rendering and user interaction
Single Responsibility
Each class should have one clear purpose:
KeystrokeListener: Monitor keyboard events
StorageManager: Persist and retrieve data
WakaTimeManager: WakaTime API integration
Observable Pattern
Use @Published for reactive state updates:
class StorageManager: ObservableObject {
@Published var dailyStats: [String: Int] = [:]
func incrementCount(...) {
dailyStats[dayString] = (dailyStats[dayString] ?? 0) + 1
// UI automatically updates
}
}
Testing
Manual Testing Checklist
Before submitting a PR:
Test on Multiple macOS Versions
If possible, test on:
- macOS 13 (Ventura) - minimum supported
- macOS 14 (Sonoma)
- macOS 15 (Sequoia)
Privacy Guidelines
NEVER:
- Record actual keystrokes or text
- Send data to external servers (except WakaTime if enabled)
- Access user files without permission
- Use analytics or tracking
ALWAYS:
- Store data locally only
- Use UserDefaults for simple data
- Ask for explicit permission (Accessibility)
- Document what data is collected
Event Handler Efficiency
The keystroke handler runs on every key press:
// Good: Minimal processing
private func handle(event: NSEvent) {
guard !isPaused else { return } // Fast exit
// Lightweight operations only
let frontmost = NSWorkspace.shared.frontmostApplication
guard let characters = event.charactersIgnoringModifiers else { return }
for char in characters {
if char.isLetter || char.isNumber || char.isPunctuation || char.isWhitespace {
DispatchQueue.main.async {
StorageManager.shared.incrementCount(...)
}
}
}
}
// Bad: Heavy processing
private func handle(event: NSEvent) {
// Don't do this in the event handler!
fetchDataFromAPI()
processLargeFile()
updateComplexUI()
}
Memory Management
Limit stored data:
// Good: Automatic pruning
if minuteStats.count > 120 {
let keys = minuteStats.keys.sorted().prefix(minuteStats.count - 120)
for key in keys { minuteStats.removeValue(forKey: key) }
}
Git Commit Messages
Write clear, descriptive commits:
# Good
git commit -m "Add project name extraction for VS Code"
git commit -m "Fix theme picker not updating preview"
git commit -m "Optimize minute stats pruning performance"
# Bad
git commit -m "fix bug"
git commit -m "update code"
git commit -m "wip"
<type>: <description>
[optional body]
Types:
feat: New feature
fix: Bug fix
refactor: Code restructuring
perf: Performance improvement
docs: Documentation
style: Formatting, no code change
test: Adding tests
Questions?
Not sure about something? Open a discussion on GitHub or comment on an existing issue.
We’re here to help!