diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..7d57942 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,62 @@ +name: release + +on: + push: + tags: ["v*"] + +env: + DL_DIR: /srv/breadway-dl + ECOSYSTEM_DIR: /home/breadway/Projects/bread-ecosystem + +jobs: + build: + runs-on: [self-hosted, hestia] + steps: + - uses: actions/checkout@v4 + + - name: install system deps + run: sudo pacman -S --noconfirm gtk4 gtk4-layer-shell librsvg 2>/dev/null || true + + - name: build + run: cargo build --release --locked + + - name: prepare artifacts + run: | + VERSION="${GITHUB_REF_NAME#v}" + PKG_DIR="${DL_DIR}/breadbox/${VERSION}" + mkdir -p "${PKG_DIR}" + for bin in breadbox breadbox-sync; do + cp "target/release/${bin}" "${PKG_DIR}/${bin}-x86_64" + strip "${PKG_DIR}/${bin}-x86_64" + sha256sum "${PKG_DIR}/${bin}-x86_64" | awk '{print $1}' \ + > "${PKG_DIR}/${bin}-x86_64.sha256" + done + cp packaging/breadbox-sync.service "${PKG_DIR}/" + cp config.example.toml "${PKG_DIR}/" + cp bakery.toml "${PKG_DIR}/bakery.toml" + ln -sfn "${PKG_DIR}" "${DL_DIR}/breadbox/latest" + + - name: ensure bread-ecosystem + run: | + 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" + + - name: upload to GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + VERSION="${GITHUB_REF_NAME#v}" + PKG_DIR="${DL_DIR}/breadbox/${VERSION}" + gh release upload "${GITHUB_REF_NAME}" \ + "${PKG_DIR}/breadbox-x86_64" \ + "${PKG_DIR}/breadbox-sync-x86_64" \ + "${PKG_DIR}/breadbox-x86_64.sha256" \ + "${PKG_DIR}/breadbox-sync-x86_64.sha256" \ + --clobber diff --git a/Cargo.lock b/Cargo.lock index 0e8046d..d72548f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,10 +26,21 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +[[package]] +name = "bread-theme" +version = "0.1.0" +dependencies = [ + "dirs", + "gtk4", + "serde", + "serde_json", +] + [[package]] name = "breadbox" version = "0.1.0" dependencies = [ + "bread-theme", "breadbox-shared", "gtk4", "gtk4-layer-shell", @@ -111,6 +122,27 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -675,6 +707,15 @@ version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +[[package]] +name = "libredox" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" +dependencies = [ + "libc", +] + [[package]] name = "litemap" version = "0.8.2" @@ -718,6 +759,12 @@ version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "pango" version = "0.22.6" @@ -796,6 +843,17 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + [[package]] name = "ring" version = "0.17.14" @@ -998,6 +1056,26 @@ version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tinystr" version = "0.8.3" @@ -1182,13 +1260,22 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1200,34 +1287,67 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1240,24 +1360,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/bakery.toml b/bakery.toml new file mode 100644 index 0000000..1f16c1f --- /dev/null +++ b/bakery.toml @@ -0,0 +1,18 @@ +name = "breadbox" +description = "App launcher for Hyprland / Wayland" +binaries = ["breadbox", "breadbox-sync"] +system_deps = ["gtk4", "gtk4-layer-shell", "librsvg"] +bread_deps = [] + +[[service]] +unit = "breadbox-sync.service" +enable = true + +[config] +dir = "~/.config/breadbox" +example = "config.example.toml" + +[install] +post_install = [ + "systemctl --user start breadbox-sync.service 2>/dev/null || breadbox-sync", +] diff --git a/breadbox/Cargo.toml b/breadbox/Cargo.toml index 343be40..47ca6ee 100644 --- a/breadbox/Cargo.toml +++ b/breadbox/Cargo.toml @@ -9,6 +9,9 @@ name = "breadbox" path = "src/main.rs" [dependencies] +# Path dep for local dev; replace with git dep on first tag: +# bread-theme = { git = "https://github.com/Breadway/bread-ecosystem", tag = "theme-v0.1.0", features = ["gtk"] } +bread-theme = { path = "../../bread-ecosystem/bread-theme", features = ["gtk"] } breadbox-shared = { path = "../breadbox-shared" } gtk4 = { version = "0.11", features = ["v4_12"] } gtk4-layer-shell = "0.8" diff --git a/breadbox/src/main.rs b/breadbox/src/main.rs index 8b63052..29338a9 100644 --- a/breadbox/src/main.rs +++ b/breadbox/src/main.rs @@ -1,3 +1,4 @@ +use bread_theme::{hex_to_rgba, load_palette, Palette}; use std::{ collections::HashMap, env, @@ -10,7 +11,7 @@ use std::{ }; use breadbox_shared::{ - config_dir, home_dir, load_all_desktop_entries, Config, DesktopEntry, IconCache, + config_dir, load_all_desktop_entries, Config, DesktopEntry, IconCache, }; use gtk4::{ gdk::Display, @@ -124,74 +125,28 @@ fn matches_term(field: &str, term: &str) -> bool { // ---- Theming ---------------------------------------------------------------- -#[derive(Debug)] -struct Palette { - bg: String, - surface: String, - fg: String, - accent: String, -} - -impl Palette { - fn catppuccin_mocha() -> Self { - Palette { - bg: "#1e1e2e".into(), - surface: "#181825".into(), - fg: "#cdd6f4".into(), - accent: "#89b4fa".into(), - } - } - - fn from_wal() -> Option { - let path = env::var("XDG_CACHE_HOME") - .map(PathBuf::from) - .unwrap_or_else(|_| home_dir().join(".cache")) - .join("wal/colors.json"); - let content = fs::read_to_string(&path).ok()?; - let v: serde_json::Value = serde_json::from_str(&content).ok()?; - - let spec = &v["special"]; - let cols = &v["colors"]; - - let bg = spec["background"].as_str()?.to_string(); - let surface = cols["color0"].as_str().unwrap_or(&bg).to_string(); - let fg = cols["color15"].as_str().unwrap_or("#cdd6f4").to_string(); - let accent = cols["color1"].as_str().unwrap_or("#89b4fa").to_string(); - - Some(Palette { bg, surface, fg, accent }) - } -} - -fn hex_to_rgba(hex: &str, alpha: f32) -> String { - let h = hex.trim_start_matches('#'); - let r = u8::from_str_radix(h.get(0..2).unwrap_or("00"), 16).unwrap_or(0); - let g = u8::from_str_radix(h.get(2..4).unwrap_or("00"), 16).unwrap_or(0); - let b = u8::from_str_radix(h.get(4..6).unwrap_or("00"), 16).unwrap_or(0); - format!("rgba({r}, {g}, {b}, {alpha})") -} - fn build_css(p: &Palette) -> String { - let bg_panel = hex_to_rgba(&p.bg, 0.60); + let bg_panel = hex_to_rgba(&p.background, 0.60); format!( - "* {{ font-family: 'JetBrainsMono Nerd Font Mono', monospace; font-size: 14px; }}\ + "* {{ font-family: 'Varela Round', sans-serif; font-size: 14px; }}\ window {{ background-color: transparent; }}\ .launcher-bg {{ background-color: {bg_panel}; border-radius: 8px;\ box-shadow: 0 8px 32px rgba(0,0,0,0.6); }}\ searchentry {{ background-color: {surface}; color: {fg}; caret-color: {accent};\ border: none; outline: none; box-shadow: none;\ - padding: 12px 16px; border-radius: 4px 4px 0 0; }}\ + padding: 12px 16px; border-radius: 6px 6px 0 0; }}\ listbox {{ background-color: transparent; padding: 4px; }}\ - row {{ padding: 5px 10px; color: {fg}; background-color: transparent;\ - border-radius: 4px; }}\ + row {{ padding: 8px 12px; color: {fg}; background-color: transparent;\ + border-radius: 6px; }}\ row:hover {{ background-color: {surface}; }}\ row:selected {{ background-color: {surface}; }}\ .app-name {{ font-size: 14px; }}\ .app-muted {{ color: {fg}; opacity: 0.6; font-size: 12px; }}\ image {{ margin-right: 8px; }}", bg_panel = bg_panel, - surface = p.surface, - fg = p.fg, - accent = p.accent, + surface = p.color0, + fg = p.foreground, + accent = p.color4, ) } @@ -334,15 +289,11 @@ fn run_ui(entries: Vec, css: String) { ); // User CSS override - let user_css_path = config_dir().join("style.css"); - if user_css_path.exists() { - let user_provider = CssProvider::new(); - user_provider.load_from_path(&user_css_path); - gtk4::style_context_add_provider_for_display( - &Display::default().expect("no display"), - &user_provider, - gtk4::STYLE_PROVIDER_PRIORITY_USER, - ); + { + use std::cell::RefCell; + let user_css_path = config_dir().join("style.css"); + let user_cell: RefCell> = RefCell::new(None); + bread_theme::gtk::apply_user_css(&user_css_path, &user_cell); } // Full-screen transparent window; clicks outside the launcher panel close it. @@ -557,7 +508,7 @@ fn main() { let manifest = load_manifest(); let entries = load_sorted_entries(&manifest, &priority); - let palette = Palette::from_wal().unwrap_or_else(Palette::catppuccin_mocha); + let palette = load_palette(); let css = build_css(&palette); run_ui(entries, css);