[codex] Polish board UI mobile flows (#6550)
## Thinking Path > - Paperclip is the board UI and control plane for supervising AI-agent companies. > - Operators repeatedly use mobile navigation, issue creation, inbox scanning, and markdown reading surfaces. > - Small layout and interaction rough edges add friction to those high-frequency workflows. > - The branch included a set of related board UI polish changes that were too small to review as many separate PRs. > - This pull request groups the remaining mobile/navigation/markdown polish into one standalone branch. > - The benefit is smoother board operation without mixing in unrelated backend feature work. ## What Changed - Tightened company settings navigation behavior on mobile. - Fixed mobile new issue dialog height and moved issue priority into the overflow controls on small screens. - Restored browser controls for home-screen app mode. - Fixed plugin-route sidebar selection on nested page loads. - Added markdown preformatted-block wrapping controls and coverage. - Kept updated issue list pages sorted by updated time in the board UI. ## Verification - `pnpm --filter @paperclipai/plugin-sdk build` - `NODE_ENV=test pnpm exec vitest run ui/src/components/Layout.test.tsx ui/src/components/MarkdownBody.test.tsx ui/src/components/MarkdownBody.wrap.test.tsx ui/src/components/NewIssueDialog.test.tsx ui/src/components/access/CompanySettingsNav.test.tsx ui/src/lib/pwa-install-mode.test.ts ui/src/pages/Inbox.test.tsx` The targeted UI tests passed. React emitted existing act-wrapping warnings in a few test files, but there were no test failures. ## Risks - Medium-low: changes span several UI surfaces, but they are mostly layout/interaction polish with targeted component tests. - Visual screenshots are not newly captured in this split PR; follow-up review should include browser/visual QA before marking ready. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI GPT-5 Codex via `codex_local`, tool-enabled coding session; exact context window not exposed by this runtime. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { memo, useState, useEffect, useRef, useCallback, useMemo, type ChangeEvent, type DragEvent, type RefObject } from "react";
|
||||
import { memo, useState, useEffect, useRef, useCallback, useMemo, type ChangeEvent, type CSSProperties, type DragEvent, type RefObject } from "react";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { IssueWorkMode } from "@paperclipai/shared";
|
||||
import { pickTextColorForSolidBg } from "@/lib/color-contrast";
|
||||
@@ -70,6 +70,7 @@ import { InlineEntitySelector, type InlineEntityOption } from "./InlineEntitySel
|
||||
|
||||
const DRAFT_KEY = "paperclip:issue-draft";
|
||||
const DEBOUNCE_MS = 800;
|
||||
const MOBILE_DIALOG_HEIGHT = "calc(100dvh - max(1rem, env(safe-area-inset-top)) - max(1rem, env(safe-area-inset-bottom)))";
|
||||
|
||||
|
||||
interface IssueDraft {
|
||||
@@ -1202,10 +1203,11 @@ export function NewIssueDialog() {
|
||||
<DialogContent
|
||||
showCloseButton={false}
|
||||
aria-describedby={undefined}
|
||||
style={{ "--new-issue-dialog-height": MOBILE_DIALOG_HEIGHT } as CSSProperties}
|
||||
className={cn(
|
||||
"flex h-[calc(100dvh-2rem)] max-h-[calc(100dvh-2rem)] flex-col gap-0 overflow-hidden p-0 sm:h-auto",
|
||||
"flex h-[var(--new-issue-dialog-height)] max-h-[var(--new-issue-dialog-height)] flex-col gap-0 overflow-hidden p-0 sm:h-auto",
|
||||
expanded
|
||||
? "sm:max-w-2xl sm:h-[calc(100dvh-2rem)]"
|
||||
? "sm:max-w-2xl sm:h-[var(--new-issue-dialog-height)]"
|
||||
: "sm:max-w-lg"
|
||||
)}
|
||||
onKeyDown={handleKeyDown}
|
||||
@@ -1868,7 +1870,11 @@ export function NewIssueDialog() {
|
||||
{/* Priority chip */}
|
||||
<Popover open={priorityOpen} onOpenChange={setPriorityOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<button className="inline-flex items-center gap-1.5 rounded-md border border-border px-2 py-1 text-xs hover:bg-accent/50 transition-colors">
|
||||
<button
|
||||
type="button"
|
||||
data-testid="new-issue-priority-chip"
|
||||
className="hidden items-center gap-1.5 rounded-md border border-border px-2 py-1 text-xs transition-colors hover:bg-accent/50 sm:inline-flex"
|
||||
>
|
||||
{currentPriority ? (
|
||||
<>
|
||||
<currentPriority.icon className={cn("h-3 w-3", currentPriority.color)} />
|
||||
@@ -1964,14 +1970,42 @@ export function NewIssueDialog() {
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
{/* More (dates) */}
|
||||
{/* More */}
|
||||
<Popover open={moreOpen} onOpenChange={setMoreOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<button className="inline-flex items-center justify-center rounded-md border border-border p-1 text-xs hover:bg-accent/50 transition-colors text-muted-foreground">
|
||||
<button
|
||||
type="button"
|
||||
data-testid="new-issue-more-menu-trigger"
|
||||
className="inline-flex items-center justify-center rounded-md border border-border p-1 text-xs text-muted-foreground transition-colors hover:bg-accent/50"
|
||||
>
|
||||
<MoreHorizontal className="h-3 w-3" />
|
||||
</button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-44 p-1" align="start">
|
||||
<PopoverContent className="w-44 p-1" align="start" data-testid="new-issue-more-menu">
|
||||
<div className="sm:hidden">
|
||||
<div className="px-2 py-1 text-[10px] font-medium uppercase text-muted-foreground">
|
||||
Priority
|
||||
</div>
|
||||
{priorities.map((p) => (
|
||||
<button
|
||||
type="button"
|
||||
key={p.value}
|
||||
data-testid={`new-issue-more-priority-${p.value}`}
|
||||
className={cn(
|
||||
"flex w-full items-center gap-2 rounded px-2 py-1.5 text-xs hover:bg-accent/50",
|
||||
p.value === priority && "bg-accent",
|
||||
)}
|
||||
onClick={() => {
|
||||
setPriority(p.value);
|
||||
setMoreOpen(false);
|
||||
}}
|
||||
>
|
||||
<p.icon className={cn("h-3 w-3", p.color)} />
|
||||
{p.label}
|
||||
</button>
|
||||
))}
|
||||
<div className="my-1 border-t border-border" />
|
||||
</div>
|
||||
<button className="flex items-center gap-2 w-full px-2 py-1.5 text-xs rounded hover:bg-accent/50 text-muted-foreground">
|
||||
<Calendar className="h-3 w-3" />
|
||||
Start date
|
||||
|
||||
Reference in New Issue
Block a user