diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e492838..8df4368 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ permissions: env: DL_DIR: /srv/breadway-dl - ECOSYSTEM_DIR: /tmp/bread-ecosystem-ci + ECOSYSTEM_DIR: /home/breadway/Projects/bread-ecosystem jobs: build: @@ -40,8 +40,12 @@ jobs: - name: ensure bread-ecosystem run: | - rm -rf "${ECOSYSTEM_DIR}" - git clone https://github.com/Breadway/bread-ecosystem.git "${ECOSYSTEM_DIR}" + if [[ -d "${ECOSYSTEM_DIR}/.git" ]]; then + git -C "${ECOSYSTEM_DIR}" pull --ff-only + else + mkdir -p "$(dirname "${ECOSYSTEM_DIR}")" + git clone https://github.com/Breadway/bread-ecosystem.git "${ECOSYSTEM_DIR}" + fi - name: regenerate index.json run: bash "${ECOSYSTEM_DIR}/scripts/gen-index.sh" diff --git a/Cargo.lock b/Cargo.lock index 756f0c3..8769946 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -304,18 +304,17 @@ dependencies = [ [[package]] name = "bread-theme" -version = "0.2.3" -source = "git+https://github.com/Breadway/bread-ecosystem?tag=v0.2.8#77417d552130281ff787e07d52541eb25e9d533b" +version = "0.1.0" +source = "git+https://github.com/Breadway/bread-ecosystem?tag=v0.1.0#6b5f4f475f66a645b08cb865e6dda8228d23679b" dependencies = [ "dirs 5.0.1", - "gtk4", "serde", "serde_json", ] [[package]] name = "breadman" -version = "0.3.4" +version = "0.3.1" dependencies = [ "anyhow", "breadpad-shared", @@ -332,7 +331,7 @@ dependencies = [ [[package]] name = "breadpad" -version = "0.3.4" +version = "0.3.1" dependencies = [ "anyhow", "breadpad-shared", @@ -351,7 +350,7 @@ dependencies = [ [[package]] name = "breadpad-shared" -version = "0.3.4" +version = "0.3.1" dependencies = [ "anyhow", "bread-theme", @@ -377,7 +376,7 @@ dependencies = [ [[package]] name = "breadpad-test" -version = "0.3.4" +version = "0.3.1" dependencies = [ "anyhow", "breadpad-shared", diff --git a/Cargo.toml b/Cargo.toml index 4092bed..af2b588 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ resolver = "2" [workspace.package] -version = "0.3.4" +version = "0.3.1" edition = "2021" license = "MIT" authors = ["Breadway"] diff --git a/README.md b/README.md index b39ea3d..02ec8a2 100644 --- a/README.md +++ b/README.md @@ -190,41 +190,8 @@ enabled = true # set false to never call Ollama [reminders] default_morning = "08:00" # what "tomorrow morning" resolves to missed_grace_minutes = 60 # how long after boot to still fire a missed reminder - -[calendar] -enabled = false # turn on CalDAV sync (see below) -url = "" # CalDAV calendar collection URL -username = "" -password = "" # app password / token recommended ``` -### Calendar sync (CalDAV) - -When `[calendar].enabled = true`, reminders and dated notes are pushed to a -CalDAV calendar as events (tracked by `caldav_uid` on each note), so they show -up alongside the rest of your calendar. - -1. Find your calendar's **collection URL**. It's the per-calendar CalDAV path, - not the server root — e.g. Nextcloud: - `https://host/remote.php/dav/calendars///`. -2. Create an **app password** for breadpad (don't use your main password): - Nextcloud → Settings → Security → *Devices & sessions* → "Create new app - password". Most CalDAV servers have an equivalent. -3. Fill in `breadpad.toml` (or BOS Settings → breadpad → Calendar): - - ```toml - [calendar] - enabled = true - url = "https://host/remote.php/dav/calendars/me/breadpad/" - username = "me" - password = "xxxx-xxxx-xxxx-xxxx" - ``` -4. Restart breadpad. New dated/reminder notes sync up; the `caldav_uid` field - links each note to its event so updates and deletes stay in step. - -If the server is unreachable, breadpad logs a warning and keeps the note -locally — sync is best-effort and never blocks capture. - --- ## Usage diff --git a/breadman/src/main.rs b/breadman/src/main.rs index d46557a..0ee89bc 100644 --- a/breadman/src/main.rs +++ b/breadman/src/main.rs @@ -4,6 +4,7 @@ use breadpad_shared::{ parser::parse_rule_based, scheduler::Scheduler, store::Store, + theme::{build_css, load_palette}, types::{Note, NoteType, RecurrenceRule}, }; use chrono::Local; @@ -923,7 +924,19 @@ fn show_add_note_window(parent: >k4::ApplicationWindow, state: AppState) { // ── CSS ─────────────────────────────────────────────────────────────────────── fn apply_css(_cfg: &Config) { - // Hot-reloads on `bread-theme reload` (recolours to the new pywal palette - // and re-reads the user's style.css). See breadpad_shared::theme::apply_live. - breadpad_shared::theme::apply_live(); + let palette = load_palette(); + let user_css = std::fs::read_to_string(breadpad_shared::config::style_css_path()).ok(); + let css = build_css(&palette, user_css.as_deref()); + + let provider = gtk4::CssProvider::new(); + provider.load_from_string(&css); + let Some(display) = gtk4::gdk::Display::default() else { + tracing::warn!("no default display; skipping CSS provider"); + return; + }; + gtk4::style_context_add_provider_for_display( + &display, + &provider, + gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION, + ); } diff --git a/breadpad-shared/Cargo.toml b/breadpad-shared/Cargo.toml index 01470f9..610c040 100644 --- a/breadpad-shared/Cargo.toml +++ b/breadpad-shared/Cargo.toml @@ -7,7 +7,7 @@ authors.workspace = true [dependencies] -bread-theme = { git = "https://github.com/Breadway/bread-ecosystem", tag = "v0.2.8", features = ["gtk"] } +bread-theme = { git = "https://github.com/Breadway/bread-ecosystem", tag = "v0.1.0" } anyhow.workspace = true tracing.workspace = true serde.workspace = true diff --git a/breadpad-shared/src/theme.rs b/breadpad-shared/src/theme.rs index cb1139a..adc76dc 100644 --- a/breadpad-shared/src/theme.rs +++ b/breadpad-shared/src/theme.rs @@ -1,34 +1,31 @@ pub use bread_theme::{load_palette, Palette}; -/// Apply breadpad/breadman's stylesheet and keep it live across palette changes. -/// [`build_css`] bundles the shared component sheet with the app's own rules from -/// the current pywal palette; `bread_theme::gtk::apply_app_css` re-runs this -/// whenever `bread-theme reload` rewrites the shared theme file, so the UI -/// recolours in place (and re-reads the user's `style.css` override too). -pub fn apply_live() { - bread_theme::gtk::apply_app_css(|| { - let palette = load_palette(); - let user_css = std::fs::read_to_string(crate::config::style_css_path()).ok(); - build_css(&palette, user_css.as_deref()) - }); -} - -/// Generate the full breadpad/breadman CSS string. The base — `@define-color` -/// palette, fonts, and generic widget styling — comes from the shared -/// `bread_theme::stylesheet`, so breadpad and breadman look identical to the -/// rest of the ecosystem. Only breadpad-specific component rules are appended. +/// Generate the full breadpad CSS string. The base colour variables come from +/// `bread-theme`; the widget rules below are breadpad-specific. pub fn build_css(palette: &Palette, user_css: Option<&str>) -> String { - // Shared ecosystem base (define-colors incl. accent, font, buttons, entries, - // switches, lists, cards, scrollbars). `overlay` here is color7 — consistent - // with every other bread app (breadpad previously mapped it to color0). - let mut css = bread_theme::stylesheet(palette); - - css.push_str( + let mut css = format!( r#" -/* breadpad/breadman-specific components */ -window { border-radius: 8px; } +@define-color bg {bg}; +@define-color fg {fg}; +@define-color red {c1}; +@define-color green {c2}; +@define-color yellow {c3}; +@define-color blue {c4}; +@define-color pink {c5}; +@define-color teal {c6}; +@define-color overlay {c0}; -.popup-entry { +* {{ + font-family: 'Varela Round', sans-serif; +}} + +window {{ + background-color: @bg; + color: @fg; + border-radius: 8px; +}} + +.popup-entry {{ background: @bg; color: @fg; border: 2px solid @blue; @@ -36,59 +33,80 @@ window { border-radius: 8px; } padding: 12px 16px; font-size: 14px; caret-color: @fg; -} +}} -.popup-entry:focus { +.popup-entry:focus {{ outline: none; border-color: @teal; -} +}} -.type-chip { +.type-chip {{ background: @overlay; - color: @on-overlay; + color: @fg; border-radius: 999px; padding: 4px 12px; font-size: 12px; margin: 4px; -} +}} -.type-chip.active { +.type-chip.active {{ background: @blue; - color: @on-accent; -} + color: @bg; +}} -.confirm-button { +.confirm-button {{ background: @blue; - color: @on-accent; + color: @bg; border: none; border-radius: 8px; padding: 8px 16px; font-weight: bold; -} +}} -.note-card { +.note-card {{ background: shade(@bg, 1.1); border-radius: 8px; padding: 12px; margin: 8px; border-left: 3px solid @blue; -} +}} -.note-card:hover { +.note-card:hover {{ background: shade(@bg, 1.2); -} +}} -.search-entry { +.search-entry {{ background: shade(@bg, 1.1); color: @fg; border: 1px solid @overlay; border-radius: 6px; padding: 8px 12px; -} +}} -.search-entry:focus { +.search-entry:focus {{ border-color: @blue; outline: none; +}} +"#, + bg = palette.background, + fg = palette.foreground, + c0 = palette.color0, + c1 = palette.color1, + c2 = palette.color2, + c3 = palette.color3, + c4 = palette.color4, + c5 = palette.color5, + c6 = palette.color6, + ); + + css.push_str(r#" +.dim-label { + color: alpha(@fg, 0.5); + font-size: 12px; +} + +.sidebar { + background: shade(@bg, 0.93); } .sidebar-row { @@ -103,7 +121,7 @@ window { border-radius: 8px; } .sidebar-row:selected { background: @blue; - color: @on-accent; + color: @bg; font-weight: 500; } @@ -199,6 +217,20 @@ window { border-radius: 8px; } } .snooze-option:hover { background: shade(@bg, 1.2); } + +entry { + background: shade(@bg, 1.1); + color: @fg; + border: 1px solid @overlay; + border-radius: 6px; + caret-color: @fg; + padding: 5px 10px; +} + +entry:focus { + border-color: @blue; + outline: none; +} "#); if let Some(extra) = user_css { diff --git a/breadpad/src/main.rs b/breadpad/src/main.rs index aa924d0..c840557 100644 --- a/breadpad/src/main.rs +++ b/breadpad/src/main.rs @@ -2,9 +2,10 @@ use anyhow::Result; use breadpad_shared::{ calendar::CalDavClient, classifier::Classifier, - config::Config, + config::{style_css_path, Config}, scheduler::Scheduler, store::Store, + theme::{build_css, load_palette}, types::{Note, NoteType}, }; use gtk4::{glib, prelude::*}; @@ -764,7 +765,19 @@ fn save_note_classified( } fn apply_css(_cfg: &Config) { - // Hot-reloads on `bread-theme reload` (recolours to the new pywal palette - // and re-reads the user's style.css). See breadpad_shared::theme::apply_live. - breadpad_shared::theme::apply_live(); + let palette = load_palette(); + let user_css = std::fs::read_to_string(style_css_path()).ok(); + let css = build_css(&palette, user_css.as_deref()); + + let provider = gtk4::CssProvider::new(); + provider.load_from_string(&css); + let Some(display) = gtk4::gdk::Display::default() else { + tracing::warn!("no default display; skipping CSS provider"); + return; + }; + gtk4::style_context_add_provider_for_display( + &display, + &provider, + gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION, + ); }