Skip to content

feat(activity): show app logos in their own colours - #70

Merged
furqan-debug merged 9 commits into
mainfrom
feat/app-icons-full-colour
Sep 22, 2026
Merged

furqan-debug merged 9 commits into
mainfrom
feat/app-icons-full-colour

Conversation

@mhuzaifa2904

Copy link
Copy Markdown
Collaborator
  • The last round put logos on about 25 apps and a plain letter on everything else. Checking against two months of real tracking data - about 286,000 records - the letter was doing most of the work: only around 6 in 10 rows had a logo. Teams, Edge, Word, Excel, Outlook, Slack, and Acrobat were all letters. It's now 95 in 100 with a proper logo.
  • Those gaps weren't a mistake on our side. The logo library we use deleted every Microsoft, Slack, Adobe, and LinkedIn logo a while back for legal reasons - they simply aren't in it anymore. The older version still has them, so that one now sits alongside purely to fill those gaps.
  • The logos we did have were flat, single-colour. Edge was a solid blue blob instead of its blue-and-green swirl. That library only ever stores one colour per logo, so the real artwork now comes from a different source that keeps the proper colours.
  • That source holds thousands of logos, and we need about 90. Instead of shipping all of it, a small script pulls out only what we use. Pages load about 48 KB heavier - nobody will notice.
  • Worth flagging: many of those logos are the wide version with the company name beside it, which becomes an unreadable smear at the size we show. I put every icon on a screen and looked at them, which is the only reason this was caught - Slack, WhatsApp, GitHub, and others were all affected. Swapped for the square ones.
  • Windows' own background processes now share the Windows logo so they read as one group. Notepad, Calculator, Settings and Snipping Tool aren't part of Windows - they're their own apps - and I'd wrongly given them the Microsoft logo earlier in this branch, making it look like they were Windows. That's undone.
  • Dialpad is the third most-used app in the company and was showing a bare "D". There is genuinely no Dialpad logo published anywhere; I searched every icon library available. So Dialpad, Settings, Calendar, Calculator, and Snipping Tool now show a small picture of what the app does - a keypad, a gear, a calendar. Not the real logo and not pretending to be, but you can tell what the app is at a glance, which a letter never gave you.
  • Notepad has its proper icon, from the image @furqan-debug sent. It arrived with a white background that would have shown as a white square, so that was cleaned off, and the image was trimmed and shrunk. Adding any other app's icon is now quick - one line and one image file.
  • Small thing that would have been an annoying bug: Notepad and Notepad++ are different apps, and the way matching works, Notepad++ would have ended up wearing Notepad's icon. Handled.
  • Still no fetching logos from the internet, same as last time. It would cover more apps automatically but would mean telling an outside company which apps every monitored employee uses, just to decorate a table.

Muhammad Huzaifa added 9 commits September 22, 2026 23:01
…erage

The App Usage list showed a logo for a couple of dozen apps and a grey
initial for everything else, including TrackOwl's own rows.

TrackOwl now renders its own owl icon on a tinted tile. The logo and
brand-colour maps grew to about 55 entries each, covering the Microsoft
family, the Windows shell processes, Slack, Dialpad, RingCentral,
MetaTrader, Acrobat and the rest of what this org actually runs.

Two matching fixes behind that:

- normalise() strips control characters. The tracker sometimes writes a
  mangled name, e.g. Spotify followed by two control bytes and "FileV".
- lookup() falls back to the longest known name the app's name starts
  with, so "Roblox Game Client" and "Steam Client WebHelper" resolve.
  Longest wins, so "google sheets" is not beaten by "google".

Checked against 60 days of activity_samples: 99.5% of 286,236 samples
now resolve to an icon or a brand tile. The remainder is "Unknown",
which keeps the neutral tile it should have.
This card had its own icon logic predating AppIcon: a globe when the
name contained "chrome" or "browser", a generic monitor otherwise. So
Zoom, Teams and Edge all sat behind the same grey monitor, and Chrome
got a globe rather than its own mark.

It now uses AppIcon, the same component the App Usage page uses, so the
two lists agree and the card picks up the full logo and brand-colour
coverage.
Teams, Edge, Word, Excel, Outlook, Slack, LinkedIn, Acrobat, VS Code and
ChatGPT were all showing a lettered tile rather than a logo. The reason
was not the lookup: simple-icons withdrew every one of those marks in
v12 under its trademark policy, so the installed v16 does not have them
at all.

Those icons are still in v11, which is now installed alongside under the
alias "brand-icons" purely to supply them. v16 stays the primary set for
everything current, including marks v11 predates such as Claude.

The Windows shell processes the tracker reports by name - Explorer,
LockApp, ShellHost, SearchHost, Calculator, Settings, Notepad and the
rest - now carry the Windows logo, so they read as one family.

Measured over 60 days of activity_samples: 96.5% of 286,236 samples now
draw a real logo, up from roughly 63%. 3.0% are small vendors no icon
set ships (Dialpad, RingCentral, WPS, MetaTrader, Balto, Antigravity,
MuMu, Scrnli) and keep an initial on a tile in the vendor's own colour -
redrawing someone's mark by eye would only get it subtly wrong. The last
0.5% is "Unknown", which keeps the neutral tile.
Mapping the Windows shell processes to the Windows mark was right for
Explorer, ShellHost, LockApp and the rest, but it swept up Notepad,
Calculator and Snipping Tool too. Those are separate apps, so the row
read as though Notepad were Windows itself.

They now take a tile in roughly the product's own accent colour. Their
real icons are not in any icon set, so this is the honest option until
the icons come off the executable itself.

Real-logo coverage moves 96.5% -> 95.1% of 286,236 samples, which is
the cost of not mislabelling 4,127 of them.
Notepad's mark is in no icon set, so it had been showing a lettered
tile. Its real artwork now ships in assets/app-icons.

The source was flat RGB with a white background, which would have read
as a white square on the tinted tile, so it was converted to RGBA with
the white knocked out, cropped to the glyph and scaled to 128px: 9.7 kB.

The owl branch generalises into IMAGE_ICONS, a map of apps whose icon is
artwork rather than a single-path mark, each with its own tile tint.
Adding another app is now one entry plus one file.

That map is matched exactly, never by prefix — the prefix pass would
otherwise hand Notepad's artwork to Notepad++, a different app that has
a mark of its own.
simple-icons ships one path and one hex per icon, so every logo came out
flat: Edge a solid blue rather than its blue-green swirl, Teams solid
purple, Chrome a single-colour disc.

The real artwork comes from the Iconify collections instead. Those hold
about 3,700 icons between them and importing either one would put all of
it in the bundle, so they are devDependencies and scripts/
generate-app-icons.mjs copies out only the icons referenced, into
src/components/ui/appIconArt.ts. Regenerate with `npm run gen:app-icons`.

Two things the generated file does deliberately:

- It prefers a collection's square "-icon" variant over the base entry.
  The base is often the full horizontal wordmark, which is an unreadable
  smudge at 40px — Slack, WhatsApp, GitHub and npm were all affected.
  Picking the square variants also cut the file from 163 kB to 102 kB.
- Icons are emitted once and referenced by every name that maps to them,
  rather than inlined per name. Twenty Windows shell processes share one
  body.

Order in the component is now artwork, then full-colour icon, then the
monochrome mark, then a brand-colour tile. Anything without artwork
keeps the mark it had, so nothing regressed.

Of 286,236 samples over 60 days: 95.5% now draw a full-colour logo, 0.8%
a monochrome mark, 3.2% a colour tile, 0.5% the neutral tile. Cost is
about 48 kB gzipped.
Settings was wearing the Windows logo, Calendar had no mapping at all,
and Dialpad — the third busiest app in the fleet at 5,526 samples — was
a lone "D" on a tile.

None of the three has a logo to fetch. Dialpad's mark is in neither
Iconify nor simple-icons; a search of the whole Iconify catalogue
returns only generic keypad pictograms, no brand mark. Windows Settings
and Calendar are the same story.

So they get a pictogram of what the app is, in the vendor's colour: a
gear for Settings, a calendar for Calendar, a keypad for Dialpad,
scissors for Snipping Tool, a calculator for Calculator. lucide-react is
already a dependency, so this costs nothing to ship. It is not the real
mark, but it reads as the app at a glance, which a letter never did.

Anything here is superseded the moment real artwork lands in
IMAGE_ICONS, the way Notepad's did.

Of 286,236 samples: 95.4% full-colour logo, 0.9% monochrome mark, 2.1%
pictogram, 1.0% colour tile, 0.5% neutral — down from 3.2% on tiles.
The control-character strip in normalise() held the literal bytes — a
real NUL, 0x1F and 0x7F sitting inside the character class rather than
the escapes for them. The regex behaved correctly and the build passed,
so it went unnoticed.

git does not read it that way: one NUL and the file is binary. It showed
no diff, no blame and no line history, which on the file under review
means a pull request that displays nothing at all.

Now written as \u0000-\u001F\u007F, which is the same character class in
text. Also drops two Windows entries left dead by the previous commit
and the comment above them, which described behaviour that had moved.
AppIcon.tsx on main carries the literal NUL byte fixed in the previous
commit, so git classes that side of the diff as binary and renders the
whole change as "Bin 14108 -> 14057 bytes". The fix commit is invisible
in review, which is precisely the commit worth reading.

Setting the diff attribute forces a textual diff regardless, and the
change reads as 335 lines again. It applies to every .tsx in the repo,
so this cannot recur silently.
@vercel

vercel Bot commented Sep 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
trackowl Ready Ready Preview Sep 22, 2026 6:59pm UTC

@furqan-debug
furqan-debug merged commit c9ff127 into main Sep 22, 2026
3 of 4 checks passed

This branch was successfully deployed

2 active deployments
Preview – trackowl — ed1458e3 Deployed Sep 22, 2026 by vercel[bot]
Preview – trackowl-admin — ed1458e3 Deployed Sep 22, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants