diff --git a/.forgejo/workflows/mirror.yml b/.forgejo/workflows/mirror.yml deleted file mode 100644 index e91c97e..0000000 --- a/.forgejo/workflows/mirror.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Mirror to GitHub - -on: - push: - branches: ['**'] - tags: ['**'] - -jobs: - mirror: - runs-on: [self-hosted, hestia] - steps: - - name: Mirror to GitHub - run: | - set -euo pipefail - git clone --mirror "https://git.breadway.dev/${GITHUB_REPOSITORY}.git" repo.git - cd repo.git - # Mirror only branches and tags (not refs/pull/*, which GitHub rejects); - # --prune deletes GitHub refs that no longer exist on Forgejo. - git push --prune \ - "https://x-access-token:${{ secrets.MIRROR_TOKEN }}@github.com/Breadway/breadpad.git" \ - '+refs/heads/*:refs/heads/*' '+refs/tags/*:refs/tags/*' diff --git a/.forgejo/workflows/package.yml b/.forgejo/workflows/package.yml deleted file mode 100644 index fdfdef9..0000000 --- a/.forgejo/workflows/package.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Build and publish package - -on: - push: - tags: ['v*'] - -jobs: - package: - runs-on: [self-hosted, hestia] - container: - image: archlinux:latest - steps: - # Note: no actions/checkout — the archlinux image has no Node, which JS - # actions require. Everything runs as shell steps and clones manually. - - name: Build and publish - env: - PUBLISH_TOKEN: ${{ secrets.REGISTRY_TOKEN }} - run: | - set -euo pipefail - VERSION="${GITHUB_REF_NAME#v}" - pacman -Syu --noconfirm base-devel git rust cargo gtk4 gtk4-layer-shell - useradd -m builder - git config --global --add safe.directory '*' - git clone --branch "${GITHUB_REF_NAME}" --depth 1 \ - "https://git.breadway.dev/${GITHUB_REPOSITORY}.git" /home/builder/src - cd /home/builder/src - git archive --format=tar.gz --prefix="breadpad-${VERSION}/" HEAD \ - > packaging/arch/breadpad-${VERSION}.tar.gz - SHA=$(sha256sum packaging/arch/breadpad-${VERSION}.tar.gz | awk '{print $1}') - sed -i "s/^pkgver=.*/pkgver=${VERSION}/" packaging/arch/PKGBUILD - sed -i "s/^sha256sums=.*/sha256sums=('${SHA}')/" packaging/arch/PKGBUILD - chown -R builder:builder /home/builder/src - # --nocheck: packaging builds the artifact; tests belong in a CI job. - su builder -c "cd /home/builder/src/packaging/arch && makepkg -f --noconfirm --nocheck" - PKG=$(find /home/builder/src/packaging/arch -name '*.pkg.tar.zst' | head -1) - curl -fsS -X PUT \ - -H "Authorization: token ${PUBLISH_TOKEN}" \ - -H "Content-Type: application/octet-stream" \ - --data-binary "@${PKG}" \ - "https://git.breadway.dev/api/packages/Breadway/arch/os" 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..be9fc6a 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.0" dependencies = [ "anyhow", "breadpad-shared", @@ -332,7 +331,7 @@ dependencies = [ [[package]] name = "breadpad" -version = "0.3.4" +version = "0.3.0" dependencies = [ "anyhow", "breadpad-shared", @@ -351,7 +350,7 @@ dependencies = [ [[package]] name = "breadpad-shared" -version = "0.3.4" +version = "0.3.0" dependencies = [ "anyhow", "bread-theme", @@ -377,7 +376,7 @@ dependencies = [ [[package]] name = "breadpad-test" -version = "0.3.4" +version = "0.3.0" dependencies = [ "anyhow", "breadpad-shared", @@ -1863,16 +1862,6 @@ version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" -[[package]] -name = "libloading" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" -dependencies = [ - "cfg-if", - "windows-link", -] - [[package]] name = "libredox" version = "0.1.17" @@ -2149,7 +2138,6 @@ version = "2.0.0-rc.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7de3af33d24a745ffb8fab904b13478438d1cd52868e6f17735ef6e1f8bf133" dependencies = [ - "libloading", "ndarray 0.17.2", "ort-sys", "smallvec", diff --git a/Cargo.toml b/Cargo.toml index 4092bed..78ae4e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ resolver = "2" [workspace.package] -version = "0.3.4" +version = "0.3.0" edition = "2021" license = "MIT" authors = ["Breadway"] @@ -24,7 +24,7 @@ chrono = { version = "0.4", features = ["serde"] } rrule = "0.12" tokio = { version = "1", features = ["full"] } zbus = { version = "4", default-features = false, features = ["tokio"] } -ort = { version = "2.0.0-rc.12", default-features = false, features = ["std", "ndarray", "tracing", "api-24", "rocm", "load-dynamic"] } +ort = { version = "2.0.0-rc.12", default-features = false, features = ["std", "ndarray", "tracing", "api-24", "rocm"] } ndarray = "0.16" tokenizers = { version = "0.21", default-features = false, features = ["http", "fancy-regex"] } gtk4 = { version = "0.11", features = ["v4_12"] } 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/bakery.toml b/bakery.toml index 25e9033..2fbc31d 100644 --- a/bakery.toml +++ b/bakery.toml @@ -1,8 +1,7 @@ name = "breadpad" description = "Quick-capture scratchpad and note viewer with AI classification" binaries = ["breadpad", "breadman"] -system_deps = ["gtk4", "gtk4-layer-shell"] -optional_system_deps = ["rocm-hip-runtime", "ollama", "hyprland"] +system_deps = ["gtk4", "gtk4-layer-shell", "rocm-runtime"] bread_deps = [] [config] 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, + ); } diff --git a/packaging/arch/PKGBUILD b/packaging/arch/PKGBUILD deleted file mode 100644 index 22511b6..0000000 --- a/packaging/arch/PKGBUILD +++ /dev/null @@ -1,38 +0,0 @@ -# Maintainer: Breadway - -pkgname=breadpad -pkgver=0.3.1 -pkgrel=1 -pkgdesc="Quick-capture scratchpad and note viewer with AI classification" -arch=('x86_64') -url="https://github.com/Breadway/breadpad" -license=('MIT') -# Some Rust deps (ring/mlua) build vendored C/asm into static archives; makepkg's -# default -flto=auto emits GCC LTO bitcode the Rust (lld) link cannot read, -# causing undefined-symbol errors. Disable LTO. -options=(!lto !debug) -depends=('gtk4' 'gtk4-layer-shell') -optdepends=( - 'ollama: local AI note classification' - 'hyprland: scratchpad window integration' -) -makedepends=('rust' 'cargo') -source=("${pkgname}-${pkgver}.tar.gz") -sha256sums=('SKIP') - -build() { - cd "${srcdir}/${pkgname}-${pkgver}" - cargo build --release --locked -} - -check() { - cd "${srcdir}/${pkgname}-${pkgver}" - cargo test --release --locked --workspace -} - -package() { - cd "${srcdir}/${pkgname}-${pkgver}" - install -Dm755 target/release/breadpad "${pkgdir}/usr/bin/breadpad" - install -Dm755 target/release/breadman "${pkgdir}/usr/bin/breadman" - install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" -}