feat(web): title the browser tab with the page being shown - #5
Conversation
Every tab of the repository said `in_pub`, so a row of them could not be told apart. Each screen now names itself as it activates, through `AppService.setPageTitle`, and the composition lives in `unpub_api/page_title.dart` — which the server reads too, stamping the same constant into the shell's `<title>` through the build-time template mechanism, so the name a tab shows before the bundle loads and the one it shows after cannot drift apart. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The hand-written changes are clean and correct, but the PR commits a large regenerated minified main.dart.js.dart bundle whose internal consistency cannot be fully verified by automated review.
Pull request overview
This PR makes the browser tab title reflect the page currently shown in the in_pub web UI, instead of a fixed in_pub on every route. The repository name and the title-composition rule are centralized in a new page_title.dart inside the unpub_api package (depended on by both server and web UI). The server stamps appTitle into the served shell's <title> via the existing build-time template mechanism ({{$APP_TITLE}}), and the AngularDart web UI overwrites the title on each navigation through AppService.setPageTitle.
Changes:
- Add shared
appTitleconstant andpageTitle([page])helper, and a server-side test covering the composition rule and the served shell template. - Replace the hardcoded
<title>in_pub</title>with theAPP_TITLEtemplate variable (source template, generatedindex.html.dart, andapp.dartwiring), regenerating the committed static bundle. - Call
setPageTitle(...)from all five routed components (home, list, detail, admin, account) with page-appropriate names.
File summaries
| File | Description |
|---|---|
unpub/lib/unpub_api/lib/page_title.dart |
New shared appTitle + pageTitle composition rule. |
unpub/test/page_title_test.dart |
Tests composition rule and that the served shell renders appTitle. |
unpub/lib/src/static/index.html.dart |
Generated shell now uses ${vars['APP_TITLE'] ?? ''}. |
unpub/lib/src/static/main.dart.js.dart |
Regenerated minified bundle (title-setting + minifier renames). |
unpub/lib/src/app.dart |
Passes APP_TITLE: appTitle into the shell template. |
unpub/CHANGELOG.md |
Documents the tab-title change under 3.6.0. |
unpub_web/web/index.html |
Source template uses {{$APP_TITLE}}. |
unpub_web/lib/app_service.dart |
Adds setPageTitle writing document.title. |
unpub_web/lib/src/{home,list,detail,admin,account}_component.dart |
Each sets its page title on activation. |
I verified the dual import paths resolve (package:in_pub/unpub_api/lib/... for the server, package:unpub_api/... for the web UI via the path dependency), that all five routed components set a title, the q?.isEmpty ?? true ? ... : ... precedence in list_component.dart is correct, and that the single index_html.content(...) caller passes APP_TITLE. No objective issues were found in the hand-written code; unpub_web has no automated test suite, so no test-coverage feedback applies there.
Review details
- Files reviewed: 13/13 changed files
- Comments generated: 0
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Every page of the web UI was served with the same fixed
<title>in_pub</title>, so a row of open tabs was indistinguishable and a bookmark carried no hint of what it pointed at.Each screen now names itself as it activates:
/in_pub/packagesPackages | in_pub/packages?q=fooSearch: foo | in_pub/packages/foofoo | in_pub/packages/foo/versions/1.2.3foo 1.2.3 | in_pub/accountAccount | in_pub/adminAdministration | in_pubWritten pub.dev's way round — the specific part first, because the first few characters are all a tab strip has room for.
How it fits together
unpub_api/page_title.dartholds the repository's name and the composition rule; it is the one package both the server and the web UI already depend on, and both write a title:appTitleinto the shell's<title>through the existing build-time template mechanism ({{$APP_TITLE}}), which is what a tab says until the bundle has loaded;AppService.setPageTitle.Written twice, the two would drift the first time the repository was renamed, and a tab would flip from one name to another on load.
Titles are set from the url rather than from fetched data, so the package screen is named while its request is still in flight — and stays named when the answer is that there is no such package.
Not included
The server still renders one cached shell for every route, so the initial HTML carries the bare repository name; the tab is corrected as soon as the application starts. Serving a per-route title would mean caching the shell and its ETag per url, which is a larger change than this is worth. Worth revisiting if link previews (Slack, crawlers) ever matter.
Verification
make build— green; the regeneratedunpub/lib/src/static/*.dartare committed as the project requires.dart analyze—unpubclean;unpub_webreports only the four pre-existingdart:htmldeprecation infos.dart testinunpub— 497 passed. The two failures aretest/auth/mongo_auth_store_test.dart(setUpAll)/(tearDownAll), which need a local MongoDB that was not running; unrelated to this change.unpub/test/page_title_test.dartcovers the composition rules and checks that the served shell really is titled through the template.🤖 Generated with Claude Code