feat: tooltips, two-column timer, font selector, tray behavior, icons, readme
- Custom tooltip directive (WCAG AAA) on every button in the app - Two-column timer layout with sticky hero and recent entries sidebar - Timer font selector with 16 monospace Google Fonts and live preview - UI font selector with 15+ Google Fonts - Close-to-tray and minimize-to-tray settings - New app icons (no-glow variants), platform icon set - Mini timer pop-out window - Favorites strip with drag-reorder and inline actions - Comprehensive README with feature documentation - Remove tracked files that belong in gitignore
This commit is contained in:
@@ -19,6 +19,7 @@ pub fn init_db(conn: &Connection) -> Result<(), rusqlite::Error> {
|
||||
"ALTER TABLE clients ADD COLUMN tax_id TEXT",
|
||||
"ALTER TABLE clients ADD COLUMN payment_terms TEXT",
|
||||
"ALTER TABLE clients ADD COLUMN notes TEXT",
|
||||
"ALTER TABLE clients ADD COLUMN currency TEXT",
|
||||
];
|
||||
for sql in &migration_columns {
|
||||
match conn.execute(sql, []) {
|
||||
@@ -52,6 +53,8 @@ pub fn init_db(conn: &Connection) -> Result<(), rusqlite::Error> {
|
||||
"ALTER TABLE projects ADD COLUMN budget_amount REAL DEFAULT NULL",
|
||||
"ALTER TABLE projects ADD COLUMN rounding_override INTEGER DEFAULT NULL",
|
||||
"ALTER TABLE projects ADD COLUMN timeline_override TEXT DEFAULT NULL",
|
||||
"ALTER TABLE projects ADD COLUMN notes TEXT",
|
||||
"ALTER TABLE projects ADD COLUMN currency TEXT",
|
||||
];
|
||||
for sql in &project_migrations {
|
||||
match conn.execute(sql, []) {
|
||||
@@ -76,9 +79,10 @@ pub fn init_db(conn: &Connection) -> Result<(), rusqlite::Error> {
|
||||
[],
|
||||
)?;
|
||||
|
||||
// Migrate tasks table - add estimated_hours column (safe to re-run)
|
||||
// Migrate tasks table (safe to re-run)
|
||||
let task_migrations = [
|
||||
"ALTER TABLE tasks ADD COLUMN estimated_hours REAL DEFAULT NULL",
|
||||
"ALTER TABLE tasks ADD COLUMN hourly_rate REAL DEFAULT NULL",
|
||||
];
|
||||
for sql in &task_migrations {
|
||||
match conn.execute(sql, []) {
|
||||
@@ -302,6 +306,22 @@ pub fn init_db(conn: &Connection) -> Result<(), rusqlite::Error> {
|
||||
[],
|
||||
)?;
|
||||
|
||||
// Migrate calendar_events table - add description column (safe to re-run)
|
||||
let calendar_migrations = [
|
||||
"ALTER TABLE calendar_events ADD COLUMN description TEXT",
|
||||
];
|
||||
for sql in &calendar_migrations {
|
||||
match conn.execute(sql, []) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
let msg = e.to_string();
|
||||
if !msg.contains("duplicate column") {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS timesheet_locks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@@ -345,6 +365,38 @@ pub fn init_db(conn: &Connection) -> Result<(), rusqlite::Error> {
|
||||
[],
|
||||
)?;
|
||||
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS invoice_payments (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
invoice_id INTEGER NOT NULL,
|
||||
amount REAL NOT NULL,
|
||||
date TEXT NOT NULL,
|
||||
method TEXT,
|
||||
notes TEXT,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (invoice_id) REFERENCES invoices(id) ON DELETE CASCADE
|
||||
)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS recurring_invoices (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
client_id INTEGER NOT NULL,
|
||||
template_id TEXT,
|
||||
line_items_json TEXT NOT NULL,
|
||||
tax_rate REAL DEFAULT 0,
|
||||
discount REAL DEFAULT 0,
|
||||
notes TEXT,
|
||||
recurrence_rule TEXT NOT NULL,
|
||||
next_due_date TEXT NOT NULL,
|
||||
enabled INTEGER DEFAULT 1,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (client_id) REFERENCES clients(id)
|
||||
)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
// Insert default settings
|
||||
conn.execute(
|
||||
"INSERT OR IGNORE INTO settings (key, value) VALUES ('hourly_rate', '50')",
|
||||
|
||||
Reference in New Issue
Block a user