fix: project list phone layout and language picker
Build and Deploy Verso / deploy (push) Successful in 14m3s

- Search bar overflow: min-width:0 on form prevents input min-content
  from overflowing flex container on narrow screens
- Remove duplicate New Project button from header row (tableTopArea
  already provides it for mobile)
- Simplify tableTopArea: single button+search layout regardless of
  isLibraryEnabled flag
- 2-line project rows on mobile: merge dash-cell-date-owner +
  dash-cell-tag into a single dash-cell-meta so date/owner/tags flow
  inline on line 2 below the project name
- Footer mobile: hide language-picker-text on mobile (icon only) to
  prevent 3rd line in 2-row footer
- Language picker: use mousedown instead of click for outside-close
  handler — click bubbling is unreliable on iOS for non-interactive
  elements; mousedown fires for all taps

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
claude
2026-06-16 11:47:32 +00:00
parent be353d53bd
commit b461343b23
5 changed files with 34 additions and 43 deletions
@@ -47,7 +47,7 @@ li.language-picker
menu.classList.toggle('show', opening)
toggle.setAttribute('aria-expanded', String(opening))
})
document.addEventListener('click', function (e) {
document.addEventListener('mousedown', function (e) {
if (!picker || !picker.contains(e.target)) close()
})
document.addEventListener('keydown', function (e) {
@@ -44,28 +44,12 @@ export function ProjectListDsNav() {
const tableTopArea = (
<div className="pt-2 pb-3 d-md-none d-flex gap-2">
{isLibraryEnabled ? (
<>
<SearchForm
inputValue={searchText}
setInputValue={setSearchText}
filter={filter}
selectedTag={selectedTag}
className="overflow-hidden flex-grow-1"
/>
{showNewProjectButton && (
<NewProjectButton
id="new-project-button-projects-table"
showAddAffiliationWidget
/>
)}
</>
) : (
<>
<NewProjectButton
id="new-project-button-projects-table"
showAddAffiliationWidget
/>
<SearchForm
inputValue={searchText}
setInputValue={setSearchText}
@@ -73,8 +57,6 @@ export function ProjectListDsNav() {
selectedTag={selectedTag}
className="overflow-hidden flex-grow-1"
/>
</>
)}
</div>
)
@@ -107,9 +89,6 @@ export function ProjectListDsNav() {
<ProjectTools />
)}
</div>
<div className="d-md-none">
<NewProjectButton id="new-project-button-mobile" />
</div>
</div>
</div>
<div className="project-ds-nav-project-list">
@@ -28,9 +28,10 @@ function ProjectListTableRow({ project, selected }: ProjectListTableRowProps) {
</a>{' '}
<InlineTags className="d-none d-md-inline" projectId={project.id} />
</td>
<td className="dash-cell-date-owner pb-0 d-md-none">
<td className="dash-cell-meta d-md-none">
<LastUpdatedCell project={project} />
{ownerName ? <ProjectListOwnerName ownerName={ownerName} /> : null}
<InlineTags projectId={project.id} className="ms-1" />
</td>
<td className="dash-cell-format d-none d-md-table-cell">
<FormatCell project={project} />
@@ -41,9 +42,6 @@ function ProjectListTableRow({ project, selected }: ProjectListTableRowProps) {
<td className="dash-cell-date d-none d-md-table-cell">
<LastUpdatedCell project={project} />
</td>
<td className="dash-cell-tag pt-0 d-md-none">
<InlineTags projectId={project.id} />
</td>
<td className="dash-cell-actions">
<div className="d-none d-lg-block">
<ActionsCell project={project} />
@@ -187,6 +187,10 @@ footer.site-footer {
display: none;
}
}
.language-picker-text {
display: none;
}
}
}
@@ -581,21 +581,27 @@ ul.project-list-filters {
padding-top: var(--spacing-02);
padding-bottom: var(--spacing-02);
}
td:not(.dash-cell-actions) {
padding-right: 55px;
}
}
.dash-cell-name,
.dash-cell-owner,
.dash-cell-date,
.dash-cell-tag,
.dash-cell-meta,
.dash-cell-actions {
display: block;
width: auto;
}
.dash-cell-name {
padding-right: 55px;
}
.dash-cell-meta {
padding-top: 0;
font-size: var(--font-size-02);
color: var(--content-secondary-themed);
}
.dash-cell-actions {
position: absolute;
top: var(--spacing-04);
@@ -698,6 +704,10 @@ form.project-search {
.form-group {
margin-bottom: 0;
}
@include media-breakpoint-down(md) {
min-width: 0; // Allow shrinking below input's intrinsic min-width in flex containers
}
}
.add-affiliation-mobile-wrapper {