mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-16 02:40:39 +09:00
feat(ui): mobile UX improvements, comment attachments, and cost breakdown
Add PWA meta tags for iOS home screen. Fix mobile properties drawer with safe area insets. Add image attachment button to comment thread. Improve sidebar with collapsible sections, project grouping, and mobile bottom nav. Show token and billing type breakdown on costs page. Fix inbox loading state to show content progressively. Various mobile overflow and layout fixes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b9dad31eb1
commit
33d549db13
16 changed files with 688 additions and 228 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { useState, useEffect, useRef, useCallback } from "react";
|
||||
import { useState, useEffect, useRef, useCallback, type ChangeEvent } from "react";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { useDialog } from "../context/DialogContext";
|
||||
import { useCompany } from "../context/CompanyContext";
|
||||
|
|
@ -31,6 +31,7 @@ import {
|
|||
Hexagon,
|
||||
Tag,
|
||||
Calendar,
|
||||
Paperclip,
|
||||
} from "lucide-react";
|
||||
import { cn } from "../lib/utils";
|
||||
import { issueStatusText, issueStatusTextDefault, priorityColor, priorityColorDefault } from "../lib/status-colors";
|
||||
|
|
@ -105,6 +106,7 @@ export function NewIssueDialog() {
|
|||
const [projectOpen, setProjectOpen] = useState(false);
|
||||
const [moreOpen, setMoreOpen] = useState(false);
|
||||
const descriptionEditorRef = useRef<MarkdownEditorRef>(null);
|
||||
const attachInputRef = useRef<HTMLInputElement | null>(null);
|
||||
|
||||
const { data: agents } = useQuery({
|
||||
queryKey: queryKeys.agents.list(selectedCompanyId!),
|
||||
|
|
@ -223,6 +225,21 @@ export function NewIssueDialog() {
|
|||
}
|
||||
}
|
||||
|
||||
async function handleAttachImage(evt: ChangeEvent<HTMLInputElement>) {
|
||||
const file = evt.target.files?.[0];
|
||||
if (!file) return;
|
||||
try {
|
||||
const asset = await uploadDescriptionImage.mutateAsync(file);
|
||||
const name = file.name || "image";
|
||||
setDescription((prev) => {
|
||||
const suffix = ``;
|
||||
return prev ? `${prev}\n\n${suffix}` : suffix;
|
||||
});
|
||||
} finally {
|
||||
if (attachInputRef.current) attachInputRef.current.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
const hasDraft = title.trim().length > 0 || description.trim().length > 0;
|
||||
const currentStatus = statuses.find((s) => s.value === status) ?? statuses[1]!;
|
||||
const currentPriority = priorities.find((p) => p.value === priority);
|
||||
|
|
@ -488,6 +505,23 @@ export function NewIssueDialog() {
|
|||
Labels
|
||||
</button>
|
||||
|
||||
{/* Attach image chip */}
|
||||
<input
|
||||
ref={attachInputRef}
|
||||
type="file"
|
||||
accept="image/png,image/jpeg,image/webp,image/gif"
|
||||
className="hidden"
|
||||
onChange={handleAttachImage}
|
||||
/>
|
||||
<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 text-muted-foreground"
|
||||
onClick={() => attachInputRef.current?.click()}
|
||||
disabled={uploadDescriptionImage.isPending}
|
||||
>
|
||||
<Paperclip className="h-3 w-3" />
|
||||
{uploadDescriptionImage.isPending ? "Uploading..." : "Image"}
|
||||
</button>
|
||||
|
||||
{/* More (dates) */}
|
||||
<Popover open={moreOpen} onOpenChange={setMoreOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue