Use full Trailhead Path Bookmarker name everywhere

- Popup header: tray icon + "Trailhead Path Bookmarker" title
- HTML <title>, electron-builder productName, and tray tooltip all match
- Popup width budget now also factors in the header's intrinsic width
  (icon + title + actions), so the brand never gets ellipsized — measured
  via h1 scrollWidth so overflow:hidden doesn't lie about content size
This commit is contained in:
David
2026-04-29 10:12:47 -04:00
parent 7150757671
commit 77c06d664b
4 changed files with 64 additions and 6 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' http://localhost:5174 ws://localhost:5174" /> <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' http://localhost:5174 ws://localhost:5174" />
<title>Folder Bookmark Tray</title> <title>Trailhead Path Bookmarker</title>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
+1 -1
View File
@@ -29,7 +29,7 @@
}, },
"build": { "build": {
"appId": "com.dbeuttel.folder-bookmark-tray", "appId": "com.dbeuttel.folder-bookmark-tray",
"productName": "Trailhead", "productName": "Trailhead Path Bookmarker",
"files": [ "files": [
"electron/**/*", "electron/**/*",
"dist/**/*", "dist/**/*",
+39 -4
View File
@@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import Column from './Column.jsx'; import Column from './Column.jsx';
import TabBar from './TabBar.jsx'; import TabBar from './TabBar.jsx';
import ConfirmDialog from './ConfirmDialog.jsx'; import ConfirmDialog from './ConfirmDialog.jsx';
import iconUrl from '../../assets/tray-icon.png';
const COLUMN_WIDTH = 216; const COLUMN_WIDTH = 216;
// Padding budget so the popup doesn't clip the tab strip: popup-inner has // Padding budget so the popup doesn't clip the tab strip: popup-inner has
@@ -41,11 +42,14 @@ export default function Popup({
const heightDebounceRef = useRef(null); const heightDebounceRef = useRef(null);
const settingsRef = useRef(null); const settingsRef = useRef(null);
const tabStripRef = useRef(null); const tabStripRef = useRef(null);
const brandRef = useRef(null);
const actionsRef = useRef(null);
const [creatingColumn, setCreatingColumn] = useState(false); const [creatingColumn, setCreatingColumn] = useState(false);
const [draftColumnName, setDraftColumnName] = useState(''); const [draftColumnName, setDraftColumnName] = useState('');
const [settingsOpen, setSettingsOpen] = useState(false); const [settingsOpen, setSettingsOpen] = useState(false);
const [confirmRequest, setConfirmRequest] = useState(null); const [confirmRequest, setConfirmRequest] = useState(null);
const [tabStripScrollWidth, setTabStripScrollWidth] = useState(0); const [tabStripScrollWidth, setTabStripScrollWidth] = useState(0);
const [headerMinWidth, setHeaderMinWidth] = useState(0);
const requestConfirm = useCallback((opts) => { const requestConfirm = useCallback((opts) => {
setConfirmRequest(opts); setConfirmRequest(opts);
@@ -86,6 +90,34 @@ export default function Popup({
}; };
}, []); }, []);
// Measure the popup header's intrinsic width so the brand never gets
// ellipsized. The h1 has overflow:hidden + text-overflow:ellipsis to keep
// it from forcing the popup wider than its content; we ask for that width
// explicitly through scrollWidth (which reports the full text width even
// when the element is clipped).
useEffect(() => {
if (!brandRef.current || !actionsRef.current) return undefined;
const update = () => {
const brand = brandRef.current;
const actions = actionsRef.current;
if (!brand || !actions) return;
const iconEl = brand.querySelector('img');
const titleEl = brand.querySelector('h1');
const iconW = iconEl ? iconEl.offsetWidth : 0;
const titleW = titleEl ? titleEl.scrollWidth : 0;
const brandW = iconW + (titleW > 0 ? 8 + titleW : 0);
const actionsW = actions.scrollWidth;
// 28px = popup-inner horizontal padding (14 each side); 8px = gap
// between brand and actions inside popup-header.
setHeaderMinWidth(brandW + 8 + actionsW + 28);
};
update();
const ro = new ResizeObserver(update);
ro.observe(brandRef.current);
ro.observe(actionsRef.current);
return () => ro.disconnect();
}, []);
// Watch the tab strip's scrollWidth so renames or new tabs widen the popup. // Watch the tab strip's scrollWidth so renames or new tabs widen the popup.
// ResizeObserver picks up both layout changes (window width changes) and // ResizeObserver picks up both layout changes (window width changes) and
// content changes (a tab rename growing the strip). // content changes (a tab rename growing the strip).
@@ -112,8 +144,8 @@ export default function Popup({
useEffect(() => { useEffect(() => {
const colsWidth = Math.max(1, visibleColumns.length || 1) * COLUMN_WIDTH; const colsWidth = Math.max(1, visibleColumns.length || 1) * COLUMN_WIDTH;
const tabsWidth = tabStripScrollWidth > 0 ? tabStripScrollWidth + TAB_STRIP_PADDING : 0; const tabsWidth = tabStripScrollWidth > 0 ? tabStripScrollWidth + TAB_STRIP_PADDING : 0;
window.bookmarks.setPopupWidth(Math.max(colsWidth, tabsWidth)); window.bookmarks.setPopupWidth(Math.max(colsWidth, tabsWidth, headerMinWidth));
}, [visibleColumns.length, tabStripScrollWidth]); }, [visibleColumns.length, tabStripScrollWidth, headerMinWidth]);
const submitNewColumn = async () => { const submitNewColumn = async () => {
const name = draftColumnName.trim(); const name = draftColumnName.trim();
@@ -152,8 +184,11 @@ export default function Popup({
<div className="popup"> <div className="popup">
<div className="popup-inner" ref={rootRef}> <div className="popup-inner" ref={rootRef}>
<div className="popup-header drag-region"> <div className="popup-header drag-region">
<h1>Trailhead</h1> <div className="popup-brand" ref={brandRef}>
<div className="header-actions"> <img src={iconUrl} alt="" className="popup-brand-icon" />
<h1>Trailhead Path Bookmarker</h1>
</div>
<div className="header-actions" ref={actionsRef}>
{!creatingColumn ? ( {!creatingColumn ? (
<button <button
className="icon-button" className="icon-button"
+23
View File
@@ -173,6 +173,25 @@ html, body { height: 100%; }
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 8px;
min-width: 0;
}
.popup-brand {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
flex: 1;
}
.popup-brand-icon {
width: 18px;
height: 18px;
flex: 0 0 auto;
-webkit-user-drag: none;
user-select: none;
pointer-events: none;
} }
.popup-header h1 { .popup-header h1 {
@@ -180,6 +199,10 @@ html, body { height: 100%; }
font-weight: 600; font-weight: 600;
margin: 0; margin: 0;
letter-spacing: 0.2px; letter-spacing: 0.2px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
} }
.header-actions { .header-actions {