From f8f0bef60cf59a7e5596ac1e9b2702961a042ed2 Mon Sep 17 00:00:00 2001 From: Nathan Nutter Date: Sat, 3 Oct 2026 15:45:23 -0500 Subject: [PATCH 1/2] Move AppIcon.icon into Assets/ An Icon Composer file at the repo root is easy to miss and reads as build output. Assets/ mirrors Xcode's top-level asset group and keeps the source out of every SwiftPM target (which would warn about unhandled files or sweep it into the resource bundle). --- Assets/AppIcon.icon/Assets/01-rear-blue.svg | 4 + Assets/AppIcon.icon/Assets/02-rear-teal.svg | 4 + .../AppIcon.icon/Assets/03-front-folder.svg | 4 + Assets/AppIcon.icon/Assets/04-git-mark.svg | 9 ++ .../AppIcon.icon/Assets/05-branch-orange.svg | 5 + Assets/AppIcon.icon/Assets/06-branch-blue.svg | 5 + Assets/AppIcon.icon/Assets/07-branch-teal.svg | 5 + Assets/AppIcon.icon/Assets/08-branch-base.svg | 4 + Assets/AppIcon.icon/icon.json | 106 ++++++++++++++++++ 9 files changed, 146 insertions(+) create mode 100644 Assets/AppIcon.icon/Assets/01-rear-blue.svg create mode 100644 Assets/AppIcon.icon/Assets/02-rear-teal.svg create mode 100644 Assets/AppIcon.icon/Assets/03-front-folder.svg create mode 100644 Assets/AppIcon.icon/Assets/04-git-mark.svg create mode 100644 Assets/AppIcon.icon/Assets/05-branch-orange.svg create mode 100644 Assets/AppIcon.icon/Assets/06-branch-blue.svg create mode 100644 Assets/AppIcon.icon/Assets/07-branch-teal.svg create mode 100644 Assets/AppIcon.icon/Assets/08-branch-base.svg create mode 100644 Assets/AppIcon.icon/icon.json diff --git a/Assets/AppIcon.icon/Assets/01-rear-blue.svg b/Assets/AppIcon.icon/Assets/01-rear-blue.svg new file mode 100644 index 0000000..a131890 --- /dev/null +++ b/Assets/AppIcon.icon/Assets/01-rear-blue.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/Assets/AppIcon.icon/Assets/02-rear-teal.svg b/Assets/AppIcon.icon/Assets/02-rear-teal.svg new file mode 100644 index 0000000..24490d0 --- /dev/null +++ b/Assets/AppIcon.icon/Assets/02-rear-teal.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/Assets/AppIcon.icon/Assets/03-front-folder.svg b/Assets/AppIcon.icon/Assets/03-front-folder.svg new file mode 100644 index 0000000..c2447a7 --- /dev/null +++ b/Assets/AppIcon.icon/Assets/03-front-folder.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/Assets/AppIcon.icon/Assets/04-git-mark.svg b/Assets/AppIcon.icon/Assets/04-git-mark.svg new file mode 100644 index 0000000..af4c34c --- /dev/null +++ b/Assets/AppIcon.icon/Assets/04-git-mark.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/Assets/AppIcon.icon/Assets/05-branch-orange.svg b/Assets/AppIcon.icon/Assets/05-branch-orange.svg new file mode 100644 index 0000000..377a54d --- /dev/null +++ b/Assets/AppIcon.icon/Assets/05-branch-orange.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Assets/AppIcon.icon/Assets/06-branch-blue.svg b/Assets/AppIcon.icon/Assets/06-branch-blue.svg new file mode 100644 index 0000000..00e597c --- /dev/null +++ b/Assets/AppIcon.icon/Assets/06-branch-blue.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Assets/AppIcon.icon/Assets/07-branch-teal.svg b/Assets/AppIcon.icon/Assets/07-branch-teal.svg new file mode 100644 index 0000000..f7d4dad --- /dev/null +++ b/Assets/AppIcon.icon/Assets/07-branch-teal.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Assets/AppIcon.icon/Assets/08-branch-base.svg b/Assets/AppIcon.icon/Assets/08-branch-base.svg new file mode 100644 index 0000000..3d1edfd --- /dev/null +++ b/Assets/AppIcon.icon/Assets/08-branch-base.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Assets/AppIcon.icon/icon.json b/Assets/AppIcon.icon/icon.json new file mode 100644 index 0000000..8df00c3 --- /dev/null +++ b/Assets/AppIcon.icon/icon.json @@ -0,0 +1,106 @@ +{ + "fill-specializations" : [ + { + "value" : { + "linear-gradient" : [ + "display-p3:0.05490,0.14118,0.38824,1.00000", + "extended-srgb:0.00000,0.53333,1.00000,1.00000" + ] + } + }, + { + "appearance" : "dark", + "value" : { + "linear-gradient" : [ + "extended-gray:0.00000,1.00000", + "display-p3:0.05490,0.14118,0.38824,1.00000" + ] + } + } + ], + "groups" : [ + { + "layers" : [ + { + "image-name" : "08-branch-base.svg", + "name" : "08-branch-base" + }, + { + "image-name" : "07-branch-teal.svg", + "name" : "07-branch-teal" + }, + { + "image-name" : "06-branch-blue.svg", + "name" : "06-branch-blue" + }, + { + "image-name" : "05-branch-orange.svg", + "name" : "05-branch-orange" + } + ], + "name" : "03 Worktree Branches", + "shadow" : { + "kind" : "layer-color", + "opacity" : 0.35 + }, + "translucency" : { + "enabled" : true, + "value" : 0.05 + } + }, + { + "layers" : [ + { + "image-name" : "04-git-mark.svg", + "name" : "04-git-mark" + }, + { + "image-name" : "03-front-folder.svg", + "name" : "03-front-folder" + } + ], + "lighting" : "combined", + "name" : "02 Repository", + "shadow" : { + "kind" : "neutral", + "opacity" : 0.5 + }, + "translucency" : { + "enabled" : true, + "value" : 0.1 + } + }, + { + "layers" : [ + { + "image-name" : "02-rear-teal.svg", + "name" : "02-rear-teal" + }, + { + "image-name" : "01-rear-blue.svg", + "name" : "01-rear-blue" + } + ], + "name" : "01 Rear Worktrees", + "refractivity" : { + "depth" : 0, + "enabled" : false, + "strength" : 0.5 + }, + "shadow" : { + "kind" : "layer-color", + "opacity" : 0.35 + }, + "translucency" : { + "enabled" : true, + "value" : 0.15 + } + } + ], + "supported-platforms" : { + "circles" : [ + "watchOS" + ], + "squares" : "shared" + } +} \ No newline at end of file From 7cbd6c4ab03aaec3ff9b888fe9a67c1cd4680864 Mon Sep 17 00:00:00 2001 From: Nathan Nutter Date: Sat, 3 Oct 2026 15:47:10 -0500 Subject: [PATCH 2/2] Use the Icon Composer icon as the app icon Compile Assets/AppIcon.icon to Assets.car with actool during mise run build, copy it into the bundle's Resources, and point CFBundleIconName at it. Verified via a full universal build: the bundled car contains the AppIcon groups and codesign verifies. --- README.md | 3 +++ mise.toml | 8 ++++++++ packaging/Info.plist | 2 ++ 3 files changed, 13 insertions(+) diff --git a/README.md b/README.md index ee4f15e..f7335cc 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,9 @@ globstar script, since macOS ships bash 3.2. `timber repo add` here has no and whitened so both render as monochrome template images). - `Sources/TimberModel/TimberModel.swift` — pure filter/argv logic ported from `TimberModel.js`, UI-independent. +- `Assets/AppIcon.icon/` — Icon Composer source for the app icon; + `mise run build` compiles it to `Assets.car` via `actool`, and + `CFBundleIconName` in `packaging/Info.plist` points at it. - `Tests/TimberModelTests/` — unit tests for the model. ## Build & run diff --git a/mise.toml b/mise.toml index da566b1..51d1f47 100644 --- a/mise.toml +++ b/mise.toml @@ -36,6 +36,14 @@ mkdir -p dist/Timber.app/Contents/MacOS dist/Timber.app/Contents/Resources lipo -create "$ARM_BIN/Timber" "$X86_BIN/Timber" -output dist/Timber.app/Contents/MacOS/Timber cp packaging/Info.plist dist/Timber.app/Contents/Info.plist cp -R "$ARM_BIN/Timber_Timber.bundle" dist/Timber.app/Contents/Resources/ +# Compile the Icon Composer source into Assets.car so the bundle gets a +# real app icon (CFBundleIconName in Info.plist points at it). actool +# exits nonzero on failure, and set -e stops the build there; its plist +# report goes to a log so success stays quiet. +ACTOOL_OUT="$(mktemp -d /tmp/timber-assets.XXXXXX)" +xcrun actool --compile "$ACTOOL_OUT" --platform macosx --minimum-deployment-target 14.0 Assets/AppIcon.icon > "$ACTOOL_OUT/actool.log" +cp "$ACTOOL_OUT"/Assets.car dist/Timber.app/Contents/Resources/ +rm -rf "$ACTOOL_OUT" # Ad-hoc sign so Gatekeeper treats a downloaded copy as an intact app # bundle instead of reporting it as damaged. Still unsigned for # Gatekeeper's notarization check, so first launch needs right-click Open. diff --git a/packaging/Info.plist b/packaging/Info.plist index 35932e9..f059724 100644 --- a/packaging/Info.plist +++ b/packaging/Info.plist @@ -8,6 +8,8 @@ Timber CFBundleExecutable Timber + CFBundleIconName + AppIcon CFBundlePackageType APPL CFBundleShortVersionString